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