xref: /linux/security/integrity/ima/ima_policy.c (revision b8b572789cde5118b2cee49d426d48fcf5b30e47)
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>
15cf222217SMimi Zohar #include <linux/fs.h>
163323eec9SMimi Zohar #include <linux/security.h>
173323eec9SMimi Zohar #include <linux/magic.h>
184af4662fSMimi Zohar #include <linux/parser.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
2038d859f9SPetko Manolov #include <linux/rculist.h>
2185865c1fSDmitry Kasatkin #include <linux/genhd.h>
2280eae209SPetko Manolov #include <linux/seq_file.h>
233323eec9SMimi Zohar 
243323eec9SMimi Zohar #include "ima.h"
253323eec9SMimi Zohar 
263323eec9SMimi Zohar /* flags definitions */
273323eec9SMimi Zohar #define IMA_FUNC	0x0001
283323eec9SMimi Zohar #define IMA_MASK	0x0002
293323eec9SMimi Zohar #define IMA_FSMAGIC	0x0004
303323eec9SMimi Zohar #define IMA_UID		0x0008
3107f6a794SMimi Zohar #define IMA_FOWNER	0x0010
3285865c1fSDmitry Kasatkin #define IMA_FSUUID	0x0020
334351c294SMimi Zohar #define IMA_INMASK	0x0040
34139069efSMimi Zohar #define IMA_EUID	0x0080
353323eec9SMimi Zohar 
362fe5d6deSMimi Zohar #define UNKNOWN		0
3745e2472eSDmitry Kasatkin #define MEASURE		0x0001	/* same as IMA_MEASURE */
3845e2472eSDmitry Kasatkin #define DONT_MEASURE	0x0002
3945e2472eSDmitry Kasatkin #define APPRAISE	0x0004	/* same as IMA_APPRAISE */
4045e2472eSDmitry Kasatkin #define DONT_APPRAISE	0x0008
41e7c568e0SPeter Moody #define AUDIT		0x0040
424af4662fSMimi Zohar 
43a756024eSRoberto Sassu int ima_policy_flag;
446ad6afa1SMimi Zohar static int temp_ima_appraise;
45a756024eSRoberto Sassu 
464af4662fSMimi Zohar #define MAX_LSM_RULES 6
474af4662fSMimi Zohar enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
484af4662fSMimi Zohar 	LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
494af4662fSMimi Zohar };
503323eec9SMimi Zohar 
5124fd03c8SMimi Zohar enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB };
5224fd03c8SMimi Zohar 
5307f6a794SMimi Zohar struct ima_rule_entry {
543323eec9SMimi Zohar 	struct list_head list;
552fe5d6deSMimi Zohar 	int action;
563323eec9SMimi Zohar 	unsigned int flags;
573323eec9SMimi Zohar 	enum ima_hooks func;
583323eec9SMimi Zohar 	int mask;
593323eec9SMimi Zohar 	unsigned long fsmagic;
6085865c1fSDmitry Kasatkin 	u8 fsuuid[16];
618b94eea4SEric W. Biederman 	kuid_t uid;
6288265322SLinus Torvalds 	kuid_t fowner;
634af4662fSMimi Zohar 	struct {
644af4662fSMimi Zohar 		void *rule;	/* LSM file metadata specific */
657163a993SMimi Zohar 		void *args_p;	/* audit value */
664af4662fSMimi Zohar 		int type;	/* audit type */
674af4662fSMimi Zohar 	} lsm[MAX_LSM_RULES];
683323eec9SMimi Zohar };
693323eec9SMimi Zohar 
705789ba3bSEric Paris /*
715789ba3bSEric Paris  * Without LSM specific knowledge, the default policy can only be
7207f6a794SMimi Zohar  * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner
734af4662fSMimi Zohar  */
745789ba3bSEric Paris 
755789ba3bSEric Paris /*
765789ba3bSEric Paris  * The minimum rule set to allow for full TCB coverage.  Measures all files
775789ba3bSEric Paris  * opened or mmap for exec and everything read by root.  Dangerous because
785789ba3bSEric Paris  * normal users can easily run the machine out of memory simply building
795789ba3bSEric Paris  * and running executables.
805789ba3bSEric Paris  */
8124fd03c8SMimi Zohar static struct ima_rule_entry dont_measure_rules[] = {
8275834fc3SEric Paris 	{.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC},
833323eec9SMimi Zohar 	{.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC},
843323eec9SMimi Zohar 	{.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC},
853323eec9SMimi Zohar 	{.action = DONT_MEASURE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC},
868445d64dSDmitry Kasatkin 	{.action = DONT_MEASURE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC},
878445d64dSDmitry Kasatkin 	{.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC},
8875834fc3SEric Paris 	{.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC},
8975834fc3SEric Paris 	{.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
906438de9fSRoberto Sassu 	{.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC,
916438de9fSRoberto Sassu 	 .flags = IMA_FSMAGIC},
9224fd03c8SMimi Zohar 	{.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}
9324fd03c8SMimi Zohar };
9424fd03c8SMimi Zohar 
9524fd03c8SMimi Zohar static struct ima_rule_entry original_measurement_rules[] = {
9616cac49fSMimi Zohar 	{.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC,
973323eec9SMimi Zohar 	 .flags = IMA_FUNC | IMA_MASK},
983323eec9SMimi Zohar 	{.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
993323eec9SMimi Zohar 	 .flags = IMA_FUNC | IMA_MASK},
10024fd03c8SMimi Zohar 	{.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
10124fd03c8SMimi Zohar 	 .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID},
10224fd03c8SMimi Zohar 	{.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
10324fd03c8SMimi Zohar 	{.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
10424fd03c8SMimi Zohar };
10524fd03c8SMimi Zohar 
10624fd03c8SMimi Zohar static struct ima_rule_entry default_measurement_rules[] = {
10724fd03c8SMimi Zohar 	{.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC,
10824fd03c8SMimi Zohar 	 .flags = IMA_FUNC | IMA_MASK},
10924fd03c8SMimi Zohar 	{.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
11024fd03c8SMimi Zohar 	 .flags = IMA_FUNC | IMA_MASK},
11124fd03c8SMimi Zohar 	{.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
11224fd03c8SMimi Zohar 	 .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_EUID},
11324fd03c8SMimi Zohar 	{.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
11424fd03c8SMimi Zohar 	 .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID},
115fdf90729SMimi Zohar 	{.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
1165a9196d7SMimi Zohar 	{.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
11719f8a847SMimi Zohar 	{.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC},
1183323eec9SMimi Zohar };
1193323eec9SMimi Zohar 
12007f6a794SMimi Zohar static struct ima_rule_entry default_appraise_rules[] = {
12107f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC},
12207f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC},
12307f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC},
12407f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC},
12507f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = RAMFS_MAGIC, .flags = IMA_FSMAGIC},
12607f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC},
12707f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC},
12807f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC},
12907f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
130cd025f7fSMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
13107f6a794SMimi Zohar 	{.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
13295ee08faSMimi Zohar #ifdef CONFIG_IMA_WRITE_POLICY
13395ee08faSMimi Zohar 	{.action = APPRAISE, .func = POLICY_CHECK,
13495ee08faSMimi Zohar 	.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
13595ee08faSMimi Zohar #endif
136c57782c1SDmitry Kasatkin #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT
13788265322SLinus Torvalds 	{.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER},
138c57782c1SDmitry Kasatkin #else
139c57782c1SDmitry Kasatkin 	/* force signature */
140c57782c1SDmitry Kasatkin 	{.action = APPRAISE, .fowner = GLOBAL_ROOT_UID,
141c57782c1SDmitry Kasatkin 	 .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED},
142c57782c1SDmitry Kasatkin #endif
14307f6a794SMimi Zohar };
1443323eec9SMimi Zohar 
14507f6a794SMimi Zohar static LIST_HEAD(ima_default_rules);
14607f6a794SMimi Zohar static LIST_HEAD(ima_policy_rules);
14738d859f9SPetko Manolov static LIST_HEAD(ima_temp_rules);
14807f6a794SMimi Zohar static struct list_head *ima_rules;
14907f6a794SMimi Zohar 
15024fd03c8SMimi Zohar static int ima_policy __initdata;
15138d859f9SPetko Manolov 
15207f6a794SMimi Zohar static int __init default_measure_policy_setup(char *str)
1535789ba3bSEric Paris {
15424fd03c8SMimi Zohar 	if (ima_policy)
15524fd03c8SMimi Zohar 		return 1;
15624fd03c8SMimi Zohar 
15724fd03c8SMimi Zohar 	ima_policy = ORIGINAL_TCB;
1585789ba3bSEric Paris 	return 1;
1595789ba3bSEric Paris }
16007f6a794SMimi Zohar __setup("ima_tcb", default_measure_policy_setup);
16107f6a794SMimi Zohar 
16224fd03c8SMimi Zohar static int __init policy_setup(char *str)
16324fd03c8SMimi Zohar {
16424fd03c8SMimi Zohar 	if (ima_policy)
16524fd03c8SMimi Zohar 		return 1;
16624fd03c8SMimi Zohar 
16724fd03c8SMimi Zohar 	if (strcmp(str, "tcb") == 0)
16824fd03c8SMimi Zohar 		ima_policy = DEFAULT_TCB;
16924fd03c8SMimi Zohar 
17024fd03c8SMimi Zohar 	return 1;
17124fd03c8SMimi Zohar }
17224fd03c8SMimi Zohar __setup("ima_policy=", policy_setup);
17324fd03c8SMimi Zohar 
17407f6a794SMimi Zohar static bool ima_use_appraise_tcb __initdata;
17507f6a794SMimi Zohar static int __init default_appraise_policy_setup(char *str)
17607f6a794SMimi Zohar {
17707f6a794SMimi Zohar 	ima_use_appraise_tcb = 1;
17807f6a794SMimi Zohar 	return 1;
17907f6a794SMimi Zohar }
18007f6a794SMimi Zohar __setup("ima_appraise_tcb", default_appraise_policy_setup);
1815789ba3bSEric Paris 
1827163a993SMimi Zohar /*
18338d859f9SPetko Manolov  * The LSM policy can be reloaded, leaving the IMA LSM based rules referring
18438d859f9SPetko Manolov  * to the old, stale LSM policy.  Update the IMA LSM based rules to reflect
18538d859f9SPetko Manolov  * the reloaded LSM policy.  We assume the rules still exist; and BUG_ON() if
18638d859f9SPetko Manolov  * they don't.
1877163a993SMimi Zohar  */
1887163a993SMimi Zohar static void ima_lsm_update_rules(void)
1897163a993SMimi Zohar {
19038d859f9SPetko Manolov 	struct ima_rule_entry *entry;
1917163a993SMimi Zohar 	int result;
1927163a993SMimi Zohar 	int i;
1937163a993SMimi Zohar 
19438d859f9SPetko Manolov 	list_for_each_entry(entry, &ima_policy_rules, list) {
1957163a993SMimi Zohar 		for (i = 0; i < MAX_LSM_RULES; i++) {
1967163a993SMimi Zohar 			if (!entry->lsm[i].rule)
1977163a993SMimi Zohar 				continue;
1987163a993SMimi Zohar 			result = security_filter_rule_init(entry->lsm[i].type,
1997163a993SMimi Zohar 							   Audit_equal,
2007163a993SMimi Zohar 							   entry->lsm[i].args_p,
2017163a993SMimi Zohar 							   &entry->lsm[i].rule);
2027163a993SMimi Zohar 			BUG_ON(!entry->lsm[i].rule);
2037163a993SMimi Zohar 		}
2047163a993SMimi Zohar 	}
2057163a993SMimi Zohar }
2067163a993SMimi Zohar 
2073323eec9SMimi Zohar /**
2083323eec9SMimi Zohar  * ima_match_rules - determine whether an inode matches the measure rule.
2093323eec9SMimi Zohar  * @rule: a pointer to a rule
2103323eec9SMimi Zohar  * @inode: a pointer to an inode
2113323eec9SMimi Zohar  * @func: LIM hook identifier
2123323eec9SMimi Zohar  * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
2133323eec9SMimi Zohar  *
2143323eec9SMimi Zohar  * Returns true on rule match, false on failure.
2153323eec9SMimi Zohar  */
2164ad87a3dSMimi Zohar static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
2174ad87a3dSMimi Zohar 			    enum ima_hooks func, int mask)
2183323eec9SMimi Zohar {
2193323eec9SMimi Zohar 	struct task_struct *tsk = current;
2203db59dd9SMimi Zohar 	const struct cred *cred = current_cred();
2214af4662fSMimi Zohar 	int i;
2223323eec9SMimi Zohar 
22309b1148eSDmitry Kasatkin 	if ((rule->flags & IMA_FUNC) &&
22409b1148eSDmitry Kasatkin 	    (rule->func != func && func != POST_SETATTR))
2253323eec9SMimi Zohar 		return false;
22609b1148eSDmitry Kasatkin 	if ((rule->flags & IMA_MASK) &&
22709b1148eSDmitry Kasatkin 	    (rule->mask != mask && func != POST_SETATTR))
2283323eec9SMimi Zohar 		return false;
2294351c294SMimi Zohar 	if ((rule->flags & IMA_INMASK) &&
2304351c294SMimi Zohar 	    (!(rule->mask & mask) && func != POST_SETATTR))
2314351c294SMimi Zohar 		return false;
2323323eec9SMimi Zohar 	if ((rule->flags & IMA_FSMAGIC)
2333323eec9SMimi Zohar 	    && rule->fsmagic != inode->i_sb->s_magic)
2343323eec9SMimi Zohar 		return false;
23585865c1fSDmitry Kasatkin 	if ((rule->flags & IMA_FSUUID) &&
23685865c1fSDmitry Kasatkin 	    memcmp(rule->fsuuid, inode->i_sb->s_uuid, sizeof(rule->fsuuid)))
23785865c1fSDmitry Kasatkin 		return false;
2388b94eea4SEric W. Biederman 	if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid))
2393323eec9SMimi Zohar 		return false;
240139069efSMimi Zohar 	if (rule->flags & IMA_EUID) {
241139069efSMimi Zohar 		if (has_capability_noaudit(current, CAP_SETUID)) {
242139069efSMimi Zohar 			if (!uid_eq(rule->uid, cred->euid)
243139069efSMimi Zohar 			    && !uid_eq(rule->uid, cred->suid)
244139069efSMimi Zohar 			    && !uid_eq(rule->uid, cred->uid))
245139069efSMimi Zohar 				return false;
246139069efSMimi Zohar 		} else if (!uid_eq(rule->uid, cred->euid))
247139069efSMimi Zohar 			return false;
248139069efSMimi Zohar 	}
249139069efSMimi Zohar 
25088265322SLinus Torvalds 	if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid))
25107f6a794SMimi Zohar 		return false;
2524af4662fSMimi Zohar 	for (i = 0; i < MAX_LSM_RULES; i++) {
25353fc0e22SMimi Zohar 		int rc = 0;
2544af4662fSMimi Zohar 		u32 osid, sid;
2557163a993SMimi Zohar 		int retried = 0;
2564af4662fSMimi Zohar 
2574af4662fSMimi Zohar 		if (!rule->lsm[i].rule)
2584af4662fSMimi Zohar 			continue;
2597163a993SMimi Zohar retry:
2604af4662fSMimi Zohar 		switch (i) {
2614af4662fSMimi Zohar 		case LSM_OBJ_USER:
2624af4662fSMimi Zohar 		case LSM_OBJ_ROLE:
2634af4662fSMimi Zohar 		case LSM_OBJ_TYPE:
2644af4662fSMimi Zohar 			security_inode_getsecid(inode, &osid);
2654af4662fSMimi Zohar 			rc = security_filter_rule_match(osid,
2664af4662fSMimi Zohar 							rule->lsm[i].type,
26753fc0e22SMimi Zohar 							Audit_equal,
2684af4662fSMimi Zohar 							rule->lsm[i].rule,
2694af4662fSMimi Zohar 							NULL);
2704af4662fSMimi Zohar 			break;
2714af4662fSMimi Zohar 		case LSM_SUBJ_USER:
2724af4662fSMimi Zohar 		case LSM_SUBJ_ROLE:
2734af4662fSMimi Zohar 		case LSM_SUBJ_TYPE:
2744af4662fSMimi Zohar 			security_task_getsecid(tsk, &sid);
2754af4662fSMimi Zohar 			rc = security_filter_rule_match(sid,
2764af4662fSMimi Zohar 							rule->lsm[i].type,
27753fc0e22SMimi Zohar 							Audit_equal,
2784af4662fSMimi Zohar 							rule->lsm[i].rule,
2794af4662fSMimi Zohar 							NULL);
2804af4662fSMimi Zohar 		default:
2814af4662fSMimi Zohar 			break;
2824af4662fSMimi Zohar 		}
2837163a993SMimi Zohar 		if ((rc < 0) && (!retried)) {
2847163a993SMimi Zohar 			retried = 1;
2857163a993SMimi Zohar 			ima_lsm_update_rules();
2867163a993SMimi Zohar 			goto retry;
2877163a993SMimi Zohar 		}
2884af4662fSMimi Zohar 		if (!rc)
2894af4662fSMimi Zohar 			return false;
2904af4662fSMimi Zohar 	}
2913323eec9SMimi Zohar 	return true;
2923323eec9SMimi Zohar }
2933323eec9SMimi Zohar 
294d79d72e0SMimi Zohar /*
295d79d72e0SMimi Zohar  * In addition to knowing that we need to appraise the file in general,
2965a73fcfaSMimi Zohar  * we need to differentiate between calling hooks, for hook specific rules.
297d79d72e0SMimi Zohar  */
2984ad87a3dSMimi Zohar static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
299d79d72e0SMimi Zohar {
3005a73fcfaSMimi Zohar 	if (!(rule->flags & IMA_FUNC))
3015a73fcfaSMimi Zohar 		return IMA_FILE_APPRAISE;
3025a73fcfaSMimi Zohar 
303d79d72e0SMimi Zohar 	switch (func) {
304d79d72e0SMimi Zohar 	case MMAP_CHECK:
305d79d72e0SMimi Zohar 		return IMA_MMAP_APPRAISE;
306d79d72e0SMimi Zohar 	case BPRM_CHECK:
307d79d72e0SMimi Zohar 		return IMA_BPRM_APPRAISE;
308d79d72e0SMimi Zohar 	case FILE_CHECK:
309c6af8efeSMimi Zohar 	case POST_SETATTR:
310d79d72e0SMimi Zohar 		return IMA_FILE_APPRAISE;
311c6af8efeSMimi Zohar 	case MODULE_CHECK ... MAX_CHECK - 1:
312c6af8efeSMimi Zohar 	default:
313c6af8efeSMimi Zohar 		return IMA_READ_APPRAISE;
314d79d72e0SMimi Zohar 	}
315d79d72e0SMimi Zohar }
316d79d72e0SMimi Zohar 
3173323eec9SMimi Zohar /**
3183323eec9SMimi Zohar  * ima_match_policy - decision based on LSM and other conditions
3193323eec9SMimi Zohar  * @inode: pointer to an inode for which the policy decision is being made
3203323eec9SMimi Zohar  * @func: IMA hook identifier
3213323eec9SMimi Zohar  * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
3223323eec9SMimi Zohar  *
3233323eec9SMimi Zohar  * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
3243323eec9SMimi Zohar  * conditions.
3253323eec9SMimi Zohar  *
32638d859f9SPetko Manolov  * Since the IMA policy may be updated multiple times we need to lock the
32738d859f9SPetko Manolov  * list when walking it.  Reads are many orders of magnitude more numerous
32838d859f9SPetko Manolov  * than writes so ima_match_policy() is classical RCU candidate.
3293323eec9SMimi Zohar  */
3302fe5d6deSMimi Zohar int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
3312fe5d6deSMimi Zohar 		     int flags)
3323323eec9SMimi Zohar {
33307f6a794SMimi Zohar 	struct ima_rule_entry *entry;
3342fe5d6deSMimi Zohar 	int action = 0, actmask = flags | (flags << 1);
3353323eec9SMimi Zohar 
33638d859f9SPetko Manolov 	rcu_read_lock();
33738d859f9SPetko Manolov 	list_for_each_entry_rcu(entry, ima_rules, list) {
3383323eec9SMimi Zohar 
3392fe5d6deSMimi Zohar 		if (!(entry->action & actmask))
3402fe5d6deSMimi Zohar 			continue;
3412fe5d6deSMimi Zohar 
3422fe5d6deSMimi Zohar 		if (!ima_match_rules(entry, inode, func, mask))
3432fe5d6deSMimi Zohar 			continue;
3442fe5d6deSMimi Zohar 
3450e5a247cSDmitry Kasatkin 		action |= entry->flags & IMA_ACTION_FLAGS;
3460e5a247cSDmitry Kasatkin 
34745e2472eSDmitry Kasatkin 		action |= entry->action & IMA_DO_MASK;
348d79d72e0SMimi Zohar 		if (entry->action & IMA_APPRAISE)
3495a73fcfaSMimi Zohar 			action |= get_subaction(entry, func);
350d79d72e0SMimi Zohar 
35145e2472eSDmitry Kasatkin 		if (entry->action & IMA_DO_MASK)
35245e2472eSDmitry Kasatkin 			actmask &= ~(entry->action | entry->action << 1);
35345e2472eSDmitry Kasatkin 		else
35445e2472eSDmitry Kasatkin 			actmask &= ~(entry->action | entry->action >> 1);
35545e2472eSDmitry Kasatkin 
3562fe5d6deSMimi Zohar 		if (!actmask)
3572fe5d6deSMimi Zohar 			break;
3583323eec9SMimi Zohar 	}
35938d859f9SPetko Manolov 	rcu_read_unlock();
3602fe5d6deSMimi Zohar 
3612fe5d6deSMimi Zohar 	return action;
3623323eec9SMimi Zohar }
3633323eec9SMimi Zohar 
364a756024eSRoberto Sassu /*
365a756024eSRoberto Sassu  * Initialize the ima_policy_flag variable based on the currently
366a756024eSRoberto Sassu  * loaded policy.  Based on this flag, the decision to short circuit
367a756024eSRoberto Sassu  * out of a function or not call the function in the first place
368a756024eSRoberto Sassu  * can be made earlier.
369a756024eSRoberto Sassu  */
370a756024eSRoberto Sassu void ima_update_policy_flag(void)
371a756024eSRoberto Sassu {
372a756024eSRoberto Sassu 	struct ima_rule_entry *entry;
373a756024eSRoberto Sassu 
374a756024eSRoberto Sassu 	list_for_each_entry(entry, ima_rules, list) {
375a756024eSRoberto Sassu 		if (entry->action & IMA_DO_MASK)
376a756024eSRoberto Sassu 			ima_policy_flag |= entry->action;
377a756024eSRoberto Sassu 	}
378a756024eSRoberto Sassu 
3796ad6afa1SMimi Zohar 	ima_appraise |= temp_ima_appraise;
380a756024eSRoberto Sassu 	if (!ima_appraise)
381a756024eSRoberto Sassu 		ima_policy_flag &= ~IMA_APPRAISE;
382a756024eSRoberto Sassu }
383a756024eSRoberto Sassu 
3843323eec9SMimi Zohar /**
3853323eec9SMimi Zohar  * ima_init_policy - initialize the default measure rules.
3863323eec9SMimi Zohar  *
38707f6a794SMimi Zohar  * ima_rules points to either the ima_default_rules or the
38807f6a794SMimi Zohar  * the new ima_policy_rules.
3893323eec9SMimi Zohar  */
390932995f0SEric Paris void __init ima_init_policy(void)
3913323eec9SMimi Zohar {
39207f6a794SMimi Zohar 	int i, measure_entries, appraise_entries;
3933323eec9SMimi Zohar 
39424fd03c8SMimi Zohar 	/* if !ima_policy set entries = 0 so we load NO default rules */
39524fd03c8SMimi Zohar 	measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0;
39607f6a794SMimi Zohar 	appraise_entries = ima_use_appraise_tcb ?
39707f6a794SMimi Zohar 			 ARRAY_SIZE(default_appraise_rules) : 0;
3985789ba3bSEric Paris 
3995577857fSDan Carpenter 	for (i = 0; i < measure_entries; i++)
40024fd03c8SMimi Zohar 		list_add_tail(&dont_measure_rules[i].list, &ima_default_rules);
40124fd03c8SMimi Zohar 
40224fd03c8SMimi Zohar 	switch (ima_policy) {
40324fd03c8SMimi Zohar 	case ORIGINAL_TCB:
40424fd03c8SMimi Zohar 		for (i = 0; i < ARRAY_SIZE(original_measurement_rules); i++)
40524fd03c8SMimi Zohar 			list_add_tail(&original_measurement_rules[i].list,
40624fd03c8SMimi Zohar 				      &ima_default_rules);
40724fd03c8SMimi Zohar 		break;
40824fd03c8SMimi Zohar 	case DEFAULT_TCB:
40924fd03c8SMimi Zohar 		for (i = 0; i < ARRAY_SIZE(default_measurement_rules); i++)
41024fd03c8SMimi Zohar 			list_add_tail(&default_measurement_rules[i].list,
41124fd03c8SMimi Zohar 				      &ima_default_rules);
41224fd03c8SMimi Zohar 	default:
41324fd03c8SMimi Zohar 		break;
41424fd03c8SMimi Zohar 	}
41507f6a794SMimi Zohar 
4165577857fSDan Carpenter 	for (i = 0; i < appraise_entries; i++) {
4175577857fSDan Carpenter 		list_add_tail(&default_appraise_rules[i].list,
41807f6a794SMimi Zohar 			      &ima_default_rules);
41995ee08faSMimi Zohar 		if (default_appraise_rules[i].func == POLICY_CHECK)
42095ee08faSMimi Zohar 			temp_ima_appraise |= IMA_APPRAISE_POLICY;
42107f6a794SMimi Zohar 	}
42207f6a794SMimi Zohar 
42307f6a794SMimi Zohar 	ima_rules = &ima_default_rules;
42495ee08faSMimi Zohar 	ima_update_policy_flag();
4253323eec9SMimi Zohar }
4264af4662fSMimi Zohar 
4270112721dSSasha Levin /* Make sure we have a valid policy, at least containing some rules. */
428c75d8e96SColin Ian King int ima_check_policy(void)
4290112721dSSasha Levin {
4300112721dSSasha Levin 	if (list_empty(&ima_temp_rules))
4310112721dSSasha Levin 		return -EINVAL;
4320112721dSSasha Levin 	return 0;
4330112721dSSasha Levin }
4340112721dSSasha Levin 
4354af4662fSMimi Zohar /**
4364af4662fSMimi Zohar  * ima_update_policy - update default_rules with new measure rules
4374af4662fSMimi Zohar  *
4384af4662fSMimi Zohar  * Called on file .release to update the default rules with a complete new
43938d859f9SPetko Manolov  * policy.  What we do here is to splice ima_policy_rules and ima_temp_rules so
44038d859f9SPetko Manolov  * they make a queue.  The policy may be updated multiple times and this is the
44138d859f9SPetko Manolov  * RCU updater.
44238d859f9SPetko Manolov  *
44338d859f9SPetko Manolov  * Policy rules are never deleted so ima_policy_flag gets zeroed only once when
44438d859f9SPetko Manolov  * we switch from the default policy to user defined.
4454af4662fSMimi Zohar  */
4464af4662fSMimi Zohar void ima_update_policy(void)
4474af4662fSMimi Zohar {
44838d859f9SPetko Manolov 	struct list_head *first, *last, *policy;
44938d859f9SPetko Manolov 
45038d859f9SPetko Manolov 	/* append current policy with the new rules */
45138d859f9SPetko Manolov 	first = (&ima_temp_rules)->next;
45238d859f9SPetko Manolov 	last = (&ima_temp_rules)->prev;
45338d859f9SPetko Manolov 	policy = &ima_policy_rules;
45438d859f9SPetko Manolov 
45538d859f9SPetko Manolov 	synchronize_rcu();
45638d859f9SPetko Manolov 
45738d859f9SPetko Manolov 	last->next = policy;
45838d859f9SPetko Manolov 	rcu_assign_pointer(list_next_rcu(policy->prev), first);
45938d859f9SPetko Manolov 	first->prev = policy->prev;
46038d859f9SPetko Manolov 	policy->prev = last;
46138d859f9SPetko Manolov 
46238d859f9SPetko Manolov 	/* prepare for the next policy rules addition */
46338d859f9SPetko Manolov 	INIT_LIST_HEAD(&ima_temp_rules);
46438d859f9SPetko Manolov 
46538d859f9SPetko Manolov 	if (ima_rules != policy) {
46638d859f9SPetko Manolov 		ima_policy_flag = 0;
46738d859f9SPetko Manolov 		ima_rules = policy;
46838d859f9SPetko Manolov 	}
469a756024eSRoberto Sassu 	ima_update_policy_flag();
4704af4662fSMimi Zohar }
4714af4662fSMimi Zohar 
4724af4662fSMimi Zohar enum {
4734af4662fSMimi Zohar 	Opt_err = -1,
4744af4662fSMimi Zohar 	Opt_measure = 1, Opt_dont_measure,
47507f6a794SMimi Zohar 	Opt_appraise, Opt_dont_appraise,
476e7c568e0SPeter Moody 	Opt_audit,
4774af4662fSMimi Zohar 	Opt_obj_user, Opt_obj_role, Opt_obj_type,
4784af4662fSMimi Zohar 	Opt_subj_user, Opt_subj_role, Opt_subj_type,
479139069efSMimi Zohar 	Opt_func, Opt_mask, Opt_fsmagic,
48080eae209SPetko Manolov 	Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner,
48180eae209SPetko Manolov 	Opt_appraise_type, Opt_permit_directio
4824af4662fSMimi Zohar };
4834af4662fSMimi Zohar 
4844af4662fSMimi Zohar static match_table_t policy_tokens = {
4854af4662fSMimi Zohar 	{Opt_measure, "measure"},
4864af4662fSMimi Zohar 	{Opt_dont_measure, "dont_measure"},
48707f6a794SMimi Zohar 	{Opt_appraise, "appraise"},
48807f6a794SMimi Zohar 	{Opt_dont_appraise, "dont_appraise"},
489e7c568e0SPeter Moody 	{Opt_audit, "audit"},
4904af4662fSMimi Zohar 	{Opt_obj_user, "obj_user=%s"},
4914af4662fSMimi Zohar 	{Opt_obj_role, "obj_role=%s"},
4924af4662fSMimi Zohar 	{Opt_obj_type, "obj_type=%s"},
4934af4662fSMimi Zohar 	{Opt_subj_user, "subj_user=%s"},
4944af4662fSMimi Zohar 	{Opt_subj_role, "subj_role=%s"},
4954af4662fSMimi Zohar 	{Opt_subj_type, "subj_type=%s"},
4964af4662fSMimi Zohar 	{Opt_func, "func=%s"},
4974af4662fSMimi Zohar 	{Opt_mask, "mask=%s"},
4984af4662fSMimi Zohar 	{Opt_fsmagic, "fsmagic=%s"},
49985865c1fSDmitry Kasatkin 	{Opt_fsuuid, "fsuuid=%s"},
5004af4662fSMimi Zohar 	{Opt_uid, "uid=%s"},
501139069efSMimi Zohar 	{Opt_euid, "euid=%s"},
50207f6a794SMimi Zohar 	{Opt_fowner, "fowner=%s"},
5030e5a247cSDmitry Kasatkin 	{Opt_appraise_type, "appraise_type=%s"},
504f9b2a735SMimi Zohar 	{Opt_permit_directio, "permit_directio"},
5054af4662fSMimi Zohar 	{Opt_err, NULL}
5064af4662fSMimi Zohar };
5074af4662fSMimi Zohar 
50807f6a794SMimi Zohar static int ima_lsm_rule_init(struct ima_rule_entry *entry,
5097163a993SMimi Zohar 			     substring_t *args, int lsm_rule, int audit_type)
5104af4662fSMimi Zohar {
5114af4662fSMimi Zohar 	int result;
5124af4662fSMimi Zohar 
5137b62e162SEric Paris 	if (entry->lsm[lsm_rule].rule)
5147b62e162SEric Paris 		return -EINVAL;
5157b62e162SEric Paris 
5167163a993SMimi Zohar 	entry->lsm[lsm_rule].args_p = match_strdup(args);
5177163a993SMimi Zohar 	if (!entry->lsm[lsm_rule].args_p)
5187163a993SMimi Zohar 		return -ENOMEM;
5197163a993SMimi Zohar 
5204af4662fSMimi Zohar 	entry->lsm[lsm_rule].type = audit_type;
5214af4662fSMimi Zohar 	result = security_filter_rule_init(entry->lsm[lsm_rule].type,
5227163a993SMimi Zohar 					   Audit_equal,
5237163a993SMimi Zohar 					   entry->lsm[lsm_rule].args_p,
5244af4662fSMimi Zohar 					   &entry->lsm[lsm_rule].rule);
5257163a993SMimi Zohar 	if (!entry->lsm[lsm_rule].rule) {
5267163a993SMimi Zohar 		kfree(entry->lsm[lsm_rule].args_p);
527867c2026SMimi Zohar 		return -EINVAL;
5287163a993SMimi Zohar 	}
5297163a993SMimi Zohar 
5304af4662fSMimi Zohar 	return result;
5314af4662fSMimi Zohar }
5324af4662fSMimi Zohar 
5332f1506cdSEric Paris static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
5342f1506cdSEric Paris {
5352f1506cdSEric Paris 	audit_log_format(ab, "%s=", key);
5362f1506cdSEric Paris 	audit_log_untrustedstring(ab, value);
5372f1506cdSEric Paris 	audit_log_format(ab, " ");
5382f1506cdSEric Paris }
5392f1506cdSEric Paris 
54007f6a794SMimi Zohar static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
5414af4662fSMimi Zohar {
5424af4662fSMimi Zohar 	struct audit_buffer *ab;
5434351c294SMimi Zohar 	char *from;
5444af4662fSMimi Zohar 	char *p;
5454af4662fSMimi Zohar 	int result = 0;
5464af4662fSMimi Zohar 
547523979adSMimi Zohar 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
5484af4662fSMimi Zohar 
5498b94eea4SEric W. Biederman 	entry->uid = INVALID_UID;
55088265322SLinus Torvalds 	entry->fowner = INVALID_UID;
551b9035b1fSEric Paris 	entry->action = UNKNOWN;
55228ef4002SEric Paris 	while ((p = strsep(&rule, " \t")) != NULL) {
5534af4662fSMimi Zohar 		substring_t args[MAX_OPT_ARGS];
5544af4662fSMimi Zohar 		int token;
5554af4662fSMimi Zohar 		unsigned long lnum;
5564af4662fSMimi Zohar 
5574af4662fSMimi Zohar 		if (result < 0)
5584af4662fSMimi Zohar 			break;
55928ef4002SEric Paris 		if ((*p == '\0') || (*p == ' ') || (*p == '\t'))
56028ef4002SEric Paris 			continue;
5614af4662fSMimi Zohar 		token = match_token(p, policy_tokens, args);
5624af4662fSMimi Zohar 		switch (token) {
5634af4662fSMimi Zohar 		case Opt_measure:
5642f1506cdSEric Paris 			ima_log_string(ab, "action", "measure");
5657b62e162SEric Paris 
5667b62e162SEric Paris 			if (entry->action != UNKNOWN)
5677b62e162SEric Paris 				result = -EINVAL;
5687b62e162SEric Paris 
5694af4662fSMimi Zohar 			entry->action = MEASURE;
5704af4662fSMimi Zohar 			break;
5714af4662fSMimi Zohar 		case Opt_dont_measure:
5722f1506cdSEric Paris 			ima_log_string(ab, "action", "dont_measure");
5737b62e162SEric Paris 
5747b62e162SEric Paris 			if (entry->action != UNKNOWN)
5757b62e162SEric Paris 				result = -EINVAL;
5767b62e162SEric Paris 
5774af4662fSMimi Zohar 			entry->action = DONT_MEASURE;
5784af4662fSMimi Zohar 			break;
57907f6a794SMimi Zohar 		case Opt_appraise:
58007f6a794SMimi Zohar 			ima_log_string(ab, "action", "appraise");
58107f6a794SMimi Zohar 
58207f6a794SMimi Zohar 			if (entry->action != UNKNOWN)
58307f6a794SMimi Zohar 				result = -EINVAL;
58407f6a794SMimi Zohar 
58507f6a794SMimi Zohar 			entry->action = APPRAISE;
58607f6a794SMimi Zohar 			break;
58707f6a794SMimi Zohar 		case Opt_dont_appraise:
58807f6a794SMimi Zohar 			ima_log_string(ab, "action", "dont_appraise");
58907f6a794SMimi Zohar 
59007f6a794SMimi Zohar 			if (entry->action != UNKNOWN)
59107f6a794SMimi Zohar 				result = -EINVAL;
59207f6a794SMimi Zohar 
59307f6a794SMimi Zohar 			entry->action = DONT_APPRAISE;
59407f6a794SMimi Zohar 			break;
595e7c568e0SPeter Moody 		case Opt_audit:
596e7c568e0SPeter Moody 			ima_log_string(ab, "action", "audit");
597e7c568e0SPeter Moody 
598e7c568e0SPeter Moody 			if (entry->action != UNKNOWN)
599e7c568e0SPeter Moody 				result = -EINVAL;
600e7c568e0SPeter Moody 
601e7c568e0SPeter Moody 			entry->action = AUDIT;
602e7c568e0SPeter Moody 			break;
6034af4662fSMimi Zohar 		case Opt_func:
6042f1506cdSEric Paris 			ima_log_string(ab, "func", args[0].from);
6057b62e162SEric Paris 
6067b62e162SEric Paris 			if (entry->func)
6077b62e162SEric Paris 				result = -EINVAL;
6087b62e162SEric Paris 
6091e93d005SMimi Zohar 			if (strcmp(args[0].from, "FILE_CHECK") == 0)
6101e93d005SMimi Zohar 				entry->func = FILE_CHECK;
6111e93d005SMimi Zohar 			/* PATH_CHECK is for backwards compat */
6121e93d005SMimi Zohar 			else if (strcmp(args[0].from, "PATH_CHECK") == 0)
6131e93d005SMimi Zohar 				entry->func = FILE_CHECK;
614fdf90729SMimi Zohar 			else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
615fdf90729SMimi Zohar 				entry->func = MODULE_CHECK;
6165a9196d7SMimi Zohar 			else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0)
6175a9196d7SMimi Zohar 				entry->func = FIRMWARE_CHECK;
61816cac49fSMimi Zohar 			else if ((strcmp(args[0].from, "FILE_MMAP") == 0)
61916cac49fSMimi Zohar 				|| (strcmp(args[0].from, "MMAP_CHECK") == 0))
62016cac49fSMimi Zohar 				entry->func = MMAP_CHECK;
6214af4662fSMimi Zohar 			else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
6224af4662fSMimi Zohar 				entry->func = BPRM_CHECK;
623d9ddf077SMimi Zohar 			else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") ==
624d9ddf077SMimi Zohar 				 0)
625d9ddf077SMimi Zohar 				entry->func = KEXEC_KERNEL_CHECK;
626d9ddf077SMimi Zohar 			else if (strcmp(args[0].from, "KEXEC_INITRAMFS_CHECK")
627d9ddf077SMimi Zohar 				 == 0)
628d9ddf077SMimi Zohar 				entry->func = KEXEC_INITRAMFS_CHECK;
62919f8a847SMimi Zohar 			else if (strcmp(args[0].from, "POLICY_CHECK") == 0)
63019f8a847SMimi Zohar 				entry->func = POLICY_CHECK;
6314af4662fSMimi Zohar 			else
6324af4662fSMimi Zohar 				result = -EINVAL;
6334af4662fSMimi Zohar 			if (!result)
6344af4662fSMimi Zohar 				entry->flags |= IMA_FUNC;
6354af4662fSMimi Zohar 			break;
6364af4662fSMimi Zohar 		case Opt_mask:
6372f1506cdSEric Paris 			ima_log_string(ab, "mask", args[0].from);
6387b62e162SEric Paris 
6397b62e162SEric Paris 			if (entry->mask)
6407b62e162SEric Paris 				result = -EINVAL;
6417b62e162SEric Paris 
6424351c294SMimi Zohar 			from = args[0].from;
6434351c294SMimi Zohar 			if (*from == '^')
6444351c294SMimi Zohar 				from++;
6454351c294SMimi Zohar 
6464351c294SMimi Zohar 			if ((strcmp(from, "MAY_EXEC")) == 0)
6474af4662fSMimi Zohar 				entry->mask = MAY_EXEC;
6484351c294SMimi Zohar 			else if (strcmp(from, "MAY_WRITE") == 0)
6494af4662fSMimi Zohar 				entry->mask = MAY_WRITE;
6504351c294SMimi Zohar 			else if (strcmp(from, "MAY_READ") == 0)
6514af4662fSMimi Zohar 				entry->mask = MAY_READ;
6524351c294SMimi Zohar 			else if (strcmp(from, "MAY_APPEND") == 0)
6534af4662fSMimi Zohar 				entry->mask = MAY_APPEND;
6544af4662fSMimi Zohar 			else
6554af4662fSMimi Zohar 				result = -EINVAL;
6564af4662fSMimi Zohar 			if (!result)
6574351c294SMimi Zohar 				entry->flags |= (*args[0].from == '^')
6584351c294SMimi Zohar 				     ? IMA_INMASK : IMA_MASK;
6594af4662fSMimi Zohar 			break;
6604af4662fSMimi Zohar 		case Opt_fsmagic:
6612f1506cdSEric Paris 			ima_log_string(ab, "fsmagic", args[0].from);
6627b62e162SEric Paris 
6637b62e162SEric Paris 			if (entry->fsmagic) {
6647b62e162SEric Paris 				result = -EINVAL;
6657b62e162SEric Paris 				break;
6667b62e162SEric Paris 			}
6677b62e162SEric Paris 
6682bb930abSDmitry Kasatkin 			result = kstrtoul(args[0].from, 16, &entry->fsmagic);
6694af4662fSMimi Zohar 			if (!result)
6704af4662fSMimi Zohar 				entry->flags |= IMA_FSMAGIC;
6714af4662fSMimi Zohar 			break;
67285865c1fSDmitry Kasatkin 		case Opt_fsuuid:
67385865c1fSDmitry Kasatkin 			ima_log_string(ab, "fsuuid", args[0].from);
67485865c1fSDmitry Kasatkin 
67585865c1fSDmitry Kasatkin 			if (memchr_inv(entry->fsuuid, 0x00,
67685865c1fSDmitry Kasatkin 				       sizeof(entry->fsuuid))) {
67785865c1fSDmitry Kasatkin 				result = -EINVAL;
67885865c1fSDmitry Kasatkin 				break;
67985865c1fSDmitry Kasatkin 			}
68085865c1fSDmitry Kasatkin 
681446d64e3SMimi Zohar 			result = blk_part_pack_uuid(args[0].from,
682446d64e3SMimi Zohar 						    entry->fsuuid);
683446d64e3SMimi Zohar 			if (!result)
68485865c1fSDmitry Kasatkin 				entry->flags |= IMA_FSUUID;
68585865c1fSDmitry Kasatkin 			break;
6864af4662fSMimi Zohar 		case Opt_uid:
6872f1506cdSEric Paris 			ima_log_string(ab, "uid", args[0].from);
688139069efSMimi Zohar 		case Opt_euid:
689139069efSMimi Zohar 			if (token == Opt_euid)
690139069efSMimi Zohar 				ima_log_string(ab, "euid", args[0].from);
6917b62e162SEric Paris 
6928b94eea4SEric W. Biederman 			if (uid_valid(entry->uid)) {
6937b62e162SEric Paris 				result = -EINVAL;
6947b62e162SEric Paris 				break;
6957b62e162SEric Paris 			}
6967b62e162SEric Paris 
69729707b20SJingoo Han 			result = kstrtoul(args[0].from, 10, &lnum);
6984af4662fSMimi Zohar 			if (!result) {
699139069efSMimi Zohar 				entry->uid = make_kuid(current_user_ns(),
700139069efSMimi Zohar 						       (uid_t) lnum);
701139069efSMimi Zohar 				if (!uid_valid(entry->uid) ||
702139069efSMimi Zohar 				    (uid_t)lnum != lnum)
7034af4662fSMimi Zohar 					result = -EINVAL;
7044af4662fSMimi Zohar 				else
705139069efSMimi Zohar 					entry->flags |= (token == Opt_uid)
706139069efSMimi Zohar 					    ? IMA_UID : IMA_EUID;
7074af4662fSMimi Zohar 			}
7084af4662fSMimi Zohar 			break;
70907f6a794SMimi Zohar 		case Opt_fowner:
71007f6a794SMimi Zohar 			ima_log_string(ab, "fowner", args[0].from);
71107f6a794SMimi Zohar 
71288265322SLinus Torvalds 			if (uid_valid(entry->fowner)) {
71307f6a794SMimi Zohar 				result = -EINVAL;
71407f6a794SMimi Zohar 				break;
71507f6a794SMimi Zohar 			}
71607f6a794SMimi Zohar 
71729707b20SJingoo Han 			result = kstrtoul(args[0].from, 10, &lnum);
71807f6a794SMimi Zohar 			if (!result) {
71988265322SLinus Torvalds 				entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum);
72088265322SLinus Torvalds 				if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum))
72107f6a794SMimi Zohar 					result = -EINVAL;
72207f6a794SMimi Zohar 				else
72307f6a794SMimi Zohar 					entry->flags |= IMA_FOWNER;
72407f6a794SMimi Zohar 			}
72507f6a794SMimi Zohar 			break;
7264af4662fSMimi Zohar 		case Opt_obj_user:
7272f1506cdSEric Paris 			ima_log_string(ab, "obj_user", args[0].from);
7287163a993SMimi Zohar 			result = ima_lsm_rule_init(entry, args,
7294af4662fSMimi Zohar 						   LSM_OBJ_USER,
7304af4662fSMimi Zohar 						   AUDIT_OBJ_USER);
7314af4662fSMimi Zohar 			break;
7324af4662fSMimi Zohar 		case Opt_obj_role:
7332f1506cdSEric Paris 			ima_log_string(ab, "obj_role", args[0].from);
7347163a993SMimi Zohar 			result = ima_lsm_rule_init(entry, args,
7354af4662fSMimi Zohar 						   LSM_OBJ_ROLE,
7364af4662fSMimi Zohar 						   AUDIT_OBJ_ROLE);
7374af4662fSMimi Zohar 			break;
7384af4662fSMimi Zohar 		case Opt_obj_type:
7392f1506cdSEric Paris 			ima_log_string(ab, "obj_type", args[0].from);
7407163a993SMimi Zohar 			result = ima_lsm_rule_init(entry, args,
7414af4662fSMimi Zohar 						   LSM_OBJ_TYPE,
7424af4662fSMimi Zohar 						   AUDIT_OBJ_TYPE);
7434af4662fSMimi Zohar 			break;
7444af4662fSMimi Zohar 		case Opt_subj_user:
7452f1506cdSEric Paris 			ima_log_string(ab, "subj_user", args[0].from);
7467163a993SMimi Zohar 			result = ima_lsm_rule_init(entry, args,
7474af4662fSMimi Zohar 						   LSM_SUBJ_USER,
7484af4662fSMimi Zohar 						   AUDIT_SUBJ_USER);
7494af4662fSMimi Zohar 			break;
7504af4662fSMimi Zohar 		case Opt_subj_role:
7512f1506cdSEric Paris 			ima_log_string(ab, "subj_role", args[0].from);
7527163a993SMimi Zohar 			result = ima_lsm_rule_init(entry, args,
7534af4662fSMimi Zohar 						   LSM_SUBJ_ROLE,
7544af4662fSMimi Zohar 						   AUDIT_SUBJ_ROLE);
7554af4662fSMimi Zohar 			break;
7564af4662fSMimi Zohar 		case Opt_subj_type:
7572f1506cdSEric Paris 			ima_log_string(ab, "subj_type", args[0].from);
7587163a993SMimi Zohar 			result = ima_lsm_rule_init(entry, args,
7594af4662fSMimi Zohar 						   LSM_SUBJ_TYPE,
7604af4662fSMimi Zohar 						   AUDIT_SUBJ_TYPE);
7614af4662fSMimi Zohar 			break;
7620e5a247cSDmitry Kasatkin 		case Opt_appraise_type:
7630e5a247cSDmitry Kasatkin 			if (entry->action != APPRAISE) {
7640e5a247cSDmitry Kasatkin 				result = -EINVAL;
7650e5a247cSDmitry Kasatkin 				break;
7660e5a247cSDmitry Kasatkin 			}
7670e5a247cSDmitry Kasatkin 
7680e5a247cSDmitry Kasatkin 			ima_log_string(ab, "appraise_type", args[0].from);
7690e5a247cSDmitry Kasatkin 			if ((strcmp(args[0].from, "imasig")) == 0)
7700e5a247cSDmitry Kasatkin 				entry->flags |= IMA_DIGSIG_REQUIRED;
7710e5a247cSDmitry Kasatkin 			else
7720e5a247cSDmitry Kasatkin 				result = -EINVAL;
7730e5a247cSDmitry Kasatkin 			break;
774f9b2a735SMimi Zohar 		case Opt_permit_directio:
775f9b2a735SMimi Zohar 			entry->flags |= IMA_PERMIT_DIRECTIO;
776f9b2a735SMimi Zohar 			break;
7774af4662fSMimi Zohar 		case Opt_err:
7782f1506cdSEric Paris 			ima_log_string(ab, "UNKNOWN", p);
779e9d393bfSEric Paris 			result = -EINVAL;
7804af4662fSMimi Zohar 			break;
7814af4662fSMimi Zohar 		}
7824af4662fSMimi Zohar 	}
7837b62e162SEric Paris 	if (!result && (entry->action == UNKNOWN))
7844af4662fSMimi Zohar 		result = -EINVAL;
785a7f2a366SMimi Zohar 	else if (entry->func == MODULE_CHECK)
7866ad6afa1SMimi Zohar 		temp_ima_appraise |= IMA_APPRAISE_MODULES;
7875a9196d7SMimi Zohar 	else if (entry->func == FIRMWARE_CHECK)
7886ad6afa1SMimi Zohar 		temp_ima_appraise |= IMA_APPRAISE_FIRMWARE;
78919f8a847SMimi Zohar 	else if (entry->func == POLICY_CHECK)
79019f8a847SMimi Zohar 		temp_ima_appraise |= IMA_APPRAISE_POLICY;
791b0d5de4dSEric Paris 	audit_log_format(ab, "res=%d", !result);
7924af4662fSMimi Zohar 	audit_log_end(ab);
7934af4662fSMimi Zohar 	return result;
7944af4662fSMimi Zohar }
7954af4662fSMimi Zohar 
7964af4662fSMimi Zohar /**
79707f6a794SMimi Zohar  * ima_parse_add_rule - add a rule to ima_policy_rules
7984af4662fSMimi Zohar  * @rule - ima measurement policy rule
7994af4662fSMimi Zohar  *
80038d859f9SPetko Manolov  * Avoid locking by allowing just one writer at a time in ima_write_policy()
8016ccd0456SEric Paris  * Returns the length of the rule parsed, an error code on failure
8024af4662fSMimi Zohar  */
8036ccd0456SEric Paris ssize_t ima_parse_add_rule(char *rule)
8044af4662fSMimi Zohar {
80552a13284SMimi Zohar 	static const char op[] = "update_policy";
8066ccd0456SEric Paris 	char *p;
80707f6a794SMimi Zohar 	struct ima_rule_entry *entry;
8086ccd0456SEric Paris 	ssize_t result, len;
8094af4662fSMimi Zohar 	int audit_info = 0;
8104af4662fSMimi Zohar 
811272a6e90SDmitry Kasatkin 	p = strsep(&rule, "\n");
812272a6e90SDmitry Kasatkin 	len = strlen(p) + 1;
8137178784fSDmitry Kasatkin 	p += strspn(p, " \t");
814272a6e90SDmitry Kasatkin 
8157178784fSDmitry Kasatkin 	if (*p == '#' || *p == '\0')
816272a6e90SDmitry Kasatkin 		return len;
817272a6e90SDmitry Kasatkin 
8184af4662fSMimi Zohar 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
8194af4662fSMimi Zohar 	if (!entry) {
8204af4662fSMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
8214af4662fSMimi Zohar 				    NULL, op, "-ENOMEM", -ENOMEM, audit_info);
8224af4662fSMimi Zohar 		return -ENOMEM;
8234af4662fSMimi Zohar 	}
8244af4662fSMimi Zohar 
8254af4662fSMimi Zohar 	INIT_LIST_HEAD(&entry->list);
8264af4662fSMimi Zohar 
8276ccd0456SEric Paris 	result = ima_parse_rule(p, entry);
8287233e3eeSEric Paris 	if (result) {
8294af4662fSMimi Zohar 		kfree(entry);
830523979adSMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
8317e9001f6SRichard Guy Briggs 				    NULL, op, "invalid-policy", result,
832523979adSMimi Zohar 				    audit_info);
8334af4662fSMimi Zohar 		return result;
8344af4662fSMimi Zohar 	}
8354af4662fSMimi Zohar 
83638d859f9SPetko Manolov 	list_add_tail(&entry->list, &ima_temp_rules);
8377233e3eeSEric Paris 
8387233e3eeSEric Paris 	return len;
8397233e3eeSEric Paris }
8407233e3eeSEric Paris 
84138d859f9SPetko Manolov /**
84238d859f9SPetko Manolov  * ima_delete_rules() called to cleanup invalid in-flight policy.
84338d859f9SPetko Manolov  * We don't need locking as we operate on the temp list, which is
84438d859f9SPetko Manolov  * different from the active one.  There is also only one user of
84538d859f9SPetko Manolov  * ima_delete_rules() at a time.
84638d859f9SPetko Manolov  */
84764c61d80SJames Morris void ima_delete_rules(void)
8484af4662fSMimi Zohar {
84907f6a794SMimi Zohar 	struct ima_rule_entry *entry, *tmp;
8507163a993SMimi Zohar 	int i;
8514af4662fSMimi Zohar 
8526ad6afa1SMimi Zohar 	temp_ima_appraise = 0;
85338d859f9SPetko Manolov 	list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
8547163a993SMimi Zohar 		for (i = 0; i < MAX_LSM_RULES; i++)
8557163a993SMimi Zohar 			kfree(entry->lsm[i].args_p);
8567163a993SMimi Zohar 
8574af4662fSMimi Zohar 		list_del(&entry->list);
8584af4662fSMimi Zohar 		kfree(entry);
8594af4662fSMimi Zohar 	}
8604af4662fSMimi Zohar }
86180eae209SPetko Manolov 
86280eae209SPetko Manolov #ifdef	CONFIG_IMA_READ_POLICY
86380eae209SPetko Manolov enum {
86480eae209SPetko Manolov 	mask_exec = 0, mask_write, mask_read, mask_append
86580eae209SPetko Manolov };
86680eae209SPetko Manolov 
86780eae209SPetko Manolov static char *mask_tokens[] = {
86880eae209SPetko Manolov 	"MAY_EXEC",
86980eae209SPetko Manolov 	"MAY_WRITE",
87080eae209SPetko Manolov 	"MAY_READ",
87180eae209SPetko Manolov 	"MAY_APPEND"
87280eae209SPetko Manolov };
87380eae209SPetko Manolov 
87480eae209SPetko Manolov enum {
87580eae209SPetko Manolov 	func_file = 0, func_mmap, func_bprm,
876d9ddf077SMimi Zohar 	func_module, func_firmware, func_post,
87719f8a847SMimi Zohar 	func_kexec_kernel, func_kexec_initramfs,
87819f8a847SMimi Zohar 	func_policy
87980eae209SPetko Manolov };
88080eae209SPetko Manolov 
88180eae209SPetko Manolov static char *func_tokens[] = {
88280eae209SPetko Manolov 	"FILE_CHECK",
88380eae209SPetko Manolov 	"MMAP_CHECK",
88480eae209SPetko Manolov 	"BPRM_CHECK",
88580eae209SPetko Manolov 	"MODULE_CHECK",
88680eae209SPetko Manolov 	"FIRMWARE_CHECK",
887cf90ea93SMimi Zohar 	"POST_SETATTR",
888d9ddf077SMimi Zohar 	"KEXEC_KERNEL_CHECK",
889d9ddf077SMimi Zohar 	"KEXEC_INITRAMFS_CHECK",
890cf90ea93SMimi Zohar 	"POLICY_CHECK"
89180eae209SPetko Manolov };
89280eae209SPetko Manolov 
89380eae209SPetko Manolov void *ima_policy_start(struct seq_file *m, loff_t *pos)
89480eae209SPetko Manolov {
89580eae209SPetko Manolov 	loff_t l = *pos;
89680eae209SPetko Manolov 	struct ima_rule_entry *entry;
89780eae209SPetko Manolov 
89880eae209SPetko Manolov 	rcu_read_lock();
89980eae209SPetko Manolov 	list_for_each_entry_rcu(entry, ima_rules, list) {
90080eae209SPetko Manolov 		if (!l--) {
90180eae209SPetko Manolov 			rcu_read_unlock();
90280eae209SPetko Manolov 			return entry;
90380eae209SPetko Manolov 		}
90480eae209SPetko Manolov 	}
90580eae209SPetko Manolov 	rcu_read_unlock();
90680eae209SPetko Manolov 	return NULL;
90780eae209SPetko Manolov }
90880eae209SPetko Manolov 
90980eae209SPetko Manolov void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
91080eae209SPetko Manolov {
91180eae209SPetko Manolov 	struct ima_rule_entry *entry = v;
91280eae209SPetko Manolov 
91380eae209SPetko Manolov 	rcu_read_lock();
91480eae209SPetko Manolov 	entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list);
91580eae209SPetko Manolov 	rcu_read_unlock();
91680eae209SPetko Manolov 	(*pos)++;
91780eae209SPetko Manolov 
91880eae209SPetko Manolov 	return (&entry->list == ima_rules) ? NULL : entry;
91980eae209SPetko Manolov }
92080eae209SPetko Manolov 
92180eae209SPetko Manolov void ima_policy_stop(struct seq_file *m, void *v)
92280eae209SPetko Manolov {
92380eae209SPetko Manolov }
92480eae209SPetko Manolov 
92580eae209SPetko Manolov #define pt(token)	policy_tokens[token + Opt_err].pattern
92680eae209SPetko Manolov #define mt(token)	mask_tokens[token]
92780eae209SPetko Manolov #define ft(token)	func_tokens[token]
92880eae209SPetko Manolov 
929b5269ab3SMimi Zohar /*
930b5269ab3SMimi Zohar  * policy_func_show - display the ima_hooks policy rule
931b5269ab3SMimi Zohar  */
932b5269ab3SMimi Zohar static void policy_func_show(struct seq_file *m, enum ima_hooks func)
933b5269ab3SMimi Zohar {
934b5269ab3SMimi Zohar 	char tbuf[64] = {0,};
935b5269ab3SMimi Zohar 
936b5269ab3SMimi Zohar 	switch (func) {
937b5269ab3SMimi Zohar 	case FILE_CHECK:
938b5269ab3SMimi Zohar 		seq_printf(m, pt(Opt_func), ft(func_file));
939b5269ab3SMimi Zohar 		break;
940b5269ab3SMimi Zohar 	case MMAP_CHECK:
941b5269ab3SMimi Zohar 		seq_printf(m, pt(Opt_func), ft(func_mmap));
942b5269ab3SMimi Zohar 		break;
943b5269ab3SMimi Zohar 	case BPRM_CHECK:
944b5269ab3SMimi Zohar 		seq_printf(m, pt(Opt_func), ft(func_bprm));
945b5269ab3SMimi Zohar 		break;
946b5269ab3SMimi Zohar 	case MODULE_CHECK:
947b5269ab3SMimi Zohar 		seq_printf(m, pt(Opt_func), ft(func_module));
948b5269ab3SMimi Zohar 		break;
949b5269ab3SMimi Zohar 	case FIRMWARE_CHECK:
950b5269ab3SMimi Zohar 		seq_printf(m, pt(Opt_func), ft(func_firmware));
951b5269ab3SMimi Zohar 		break;
952b5269ab3SMimi Zohar 	case POST_SETATTR:
953b5269ab3SMimi Zohar 		seq_printf(m, pt(Opt_func), ft(func_post));
954b5269ab3SMimi Zohar 		break;
955d9ddf077SMimi Zohar 	case KEXEC_KERNEL_CHECK:
956d9ddf077SMimi Zohar 		seq_printf(m, pt(Opt_func), ft(func_kexec_kernel));
957d9ddf077SMimi Zohar 		break;
958d9ddf077SMimi Zohar 	case KEXEC_INITRAMFS_CHECK:
959d9ddf077SMimi Zohar 		seq_printf(m, pt(Opt_func), ft(func_kexec_initramfs));
960d9ddf077SMimi Zohar 		break;
96119f8a847SMimi Zohar 	case POLICY_CHECK:
96219f8a847SMimi Zohar 		seq_printf(m, pt(Opt_func), ft(func_policy));
96319f8a847SMimi Zohar 		break;
964b5269ab3SMimi Zohar 	default:
965b5269ab3SMimi Zohar 		snprintf(tbuf, sizeof(tbuf), "%d", func);
966b5269ab3SMimi Zohar 		seq_printf(m, pt(Opt_func), tbuf);
967b5269ab3SMimi Zohar 		break;
968b5269ab3SMimi Zohar 	}
969b5269ab3SMimi Zohar 	seq_puts(m, " ");
970b5269ab3SMimi Zohar }
971b5269ab3SMimi Zohar 
97280eae209SPetko Manolov int ima_policy_show(struct seq_file *m, void *v)
97380eae209SPetko Manolov {
97480eae209SPetko Manolov 	struct ima_rule_entry *entry = v;
975*b8b57278SAndy Shevchenko 	int i;
97680eae209SPetko Manolov 	char tbuf[64] = {0,};
97780eae209SPetko Manolov 
97880eae209SPetko Manolov 	rcu_read_lock();
97980eae209SPetko Manolov 
98080eae209SPetko Manolov 	if (entry->action & MEASURE)
98180eae209SPetko Manolov 		seq_puts(m, pt(Opt_measure));
98280eae209SPetko Manolov 	if (entry->action & DONT_MEASURE)
98380eae209SPetko Manolov 		seq_puts(m, pt(Opt_dont_measure));
98480eae209SPetko Manolov 	if (entry->action & APPRAISE)
98580eae209SPetko Manolov 		seq_puts(m, pt(Opt_appraise));
98680eae209SPetko Manolov 	if (entry->action & DONT_APPRAISE)
98780eae209SPetko Manolov 		seq_puts(m, pt(Opt_dont_appraise));
98880eae209SPetko Manolov 	if (entry->action & AUDIT)
98980eae209SPetko Manolov 		seq_puts(m, pt(Opt_audit));
99080eae209SPetko Manolov 
99180eae209SPetko Manolov 	seq_puts(m, " ");
99280eae209SPetko Manolov 
993b5269ab3SMimi Zohar 	if (entry->flags & IMA_FUNC)
994b5269ab3SMimi Zohar 		policy_func_show(m, entry->func);
99580eae209SPetko Manolov 
99680eae209SPetko Manolov 	if (entry->flags & IMA_MASK) {
99780eae209SPetko Manolov 		if (entry->mask & MAY_EXEC)
99880eae209SPetko Manolov 			seq_printf(m, pt(Opt_mask), mt(mask_exec));
99980eae209SPetko Manolov 		if (entry->mask & MAY_WRITE)
100080eae209SPetko Manolov 			seq_printf(m, pt(Opt_mask), mt(mask_write));
100180eae209SPetko Manolov 		if (entry->mask & MAY_READ)
100280eae209SPetko Manolov 			seq_printf(m, pt(Opt_mask), mt(mask_read));
100380eae209SPetko Manolov 		if (entry->mask & MAY_APPEND)
100480eae209SPetko Manolov 			seq_printf(m, pt(Opt_mask), mt(mask_append));
100580eae209SPetko Manolov 		seq_puts(m, " ");
100680eae209SPetko Manolov 	}
100780eae209SPetko Manolov 
100880eae209SPetko Manolov 	if (entry->flags & IMA_FSMAGIC) {
100980eae209SPetko Manolov 		snprintf(tbuf, sizeof(tbuf), "0x%lx", entry->fsmagic);
101080eae209SPetko Manolov 		seq_printf(m, pt(Opt_fsmagic), tbuf);
101180eae209SPetko Manolov 		seq_puts(m, " ");
101280eae209SPetko Manolov 	}
101380eae209SPetko Manolov 
101480eae209SPetko Manolov 	if (entry->flags & IMA_FSUUID) {
1015*b8b57278SAndy Shevchenko 		seq_printf(m, "fsuuid=%pU", entry->fsuuid);
101680eae209SPetko Manolov 		seq_puts(m, " ");
101780eae209SPetko Manolov 	}
101880eae209SPetko Manolov 
101980eae209SPetko Manolov 	if (entry->flags & IMA_UID) {
102080eae209SPetko Manolov 		snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
102180eae209SPetko Manolov 		seq_printf(m, pt(Opt_uid), tbuf);
102280eae209SPetko Manolov 		seq_puts(m, " ");
102380eae209SPetko Manolov 	}
102480eae209SPetko Manolov 
102580eae209SPetko Manolov 	if (entry->flags & IMA_EUID) {
102680eae209SPetko Manolov 		snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
102780eae209SPetko Manolov 		seq_printf(m, pt(Opt_euid), tbuf);
102880eae209SPetko Manolov 		seq_puts(m, " ");
102980eae209SPetko Manolov 	}
103080eae209SPetko Manolov 
103180eae209SPetko Manolov 	if (entry->flags & IMA_FOWNER) {
103280eae209SPetko Manolov 		snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
103380eae209SPetko Manolov 		seq_printf(m, pt(Opt_fowner), tbuf);
103480eae209SPetko Manolov 		seq_puts(m, " ");
103580eae209SPetko Manolov 	}
103680eae209SPetko Manolov 
103780eae209SPetko Manolov 	for (i = 0; i < MAX_LSM_RULES; i++) {
103880eae209SPetko Manolov 		if (entry->lsm[i].rule) {
103980eae209SPetko Manolov 			switch (i) {
104080eae209SPetko Manolov 			case LSM_OBJ_USER:
104180eae209SPetko Manolov 				seq_printf(m, pt(Opt_obj_user),
104280eae209SPetko Manolov 					   (char *)entry->lsm[i].args_p);
104380eae209SPetko Manolov 				break;
104480eae209SPetko Manolov 			case LSM_OBJ_ROLE:
104580eae209SPetko Manolov 				seq_printf(m, pt(Opt_obj_role),
104680eae209SPetko Manolov 					   (char *)entry->lsm[i].args_p);
104780eae209SPetko Manolov 				break;
104880eae209SPetko Manolov 			case LSM_OBJ_TYPE:
104980eae209SPetko Manolov 				seq_printf(m, pt(Opt_obj_type),
105080eae209SPetko Manolov 					   (char *)entry->lsm[i].args_p);
105180eae209SPetko Manolov 				break;
105280eae209SPetko Manolov 			case LSM_SUBJ_USER:
105380eae209SPetko Manolov 				seq_printf(m, pt(Opt_subj_user),
105480eae209SPetko Manolov 					   (char *)entry->lsm[i].args_p);
105580eae209SPetko Manolov 				break;
105680eae209SPetko Manolov 			case LSM_SUBJ_ROLE:
105780eae209SPetko Manolov 				seq_printf(m, pt(Opt_subj_role),
105880eae209SPetko Manolov 					   (char *)entry->lsm[i].args_p);
105980eae209SPetko Manolov 				break;
106080eae209SPetko Manolov 			case LSM_SUBJ_TYPE:
106180eae209SPetko Manolov 				seq_printf(m, pt(Opt_subj_type),
106280eae209SPetko Manolov 					   (char *)entry->lsm[i].args_p);
106380eae209SPetko Manolov 				break;
106480eae209SPetko Manolov 			}
106580eae209SPetko Manolov 		}
106680eae209SPetko Manolov 	}
106780eae209SPetko Manolov 	if (entry->flags & IMA_DIGSIG_REQUIRED)
106880eae209SPetko Manolov 		seq_puts(m, "appraise_type=imasig ");
106980eae209SPetko Manolov 	if (entry->flags & IMA_PERMIT_DIRECTIO)
107080eae209SPetko Manolov 		seq_puts(m, "permit_directio ");
107180eae209SPetko Manolov 	rcu_read_unlock();
107280eae209SPetko Manolov 	seq_puts(m, "\n");
107380eae209SPetko Manolov 	return 0;
107480eae209SPetko Manolov }
107580eae209SPetko Manolov #endif	/* CONFIG_IMA_READ_POLICY */
1076