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