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 350260643cSEric Richter #define IMA_PCR 0x0100 36f1b08bbcSMimi Zohar #define IMA_FSNAME 0x0200 373323eec9SMimi Zohar 382fe5d6deSMimi Zohar #define UNKNOWN 0 3945e2472eSDmitry Kasatkin #define MEASURE 0x0001 /* same as IMA_MEASURE */ 4045e2472eSDmitry Kasatkin #define DONT_MEASURE 0x0002 4145e2472eSDmitry Kasatkin #define APPRAISE 0x0004 /* same as IMA_APPRAISE */ 4245e2472eSDmitry Kasatkin #define DONT_APPRAISE 0x0008 43e7c568e0SPeter Moody #define AUDIT 0x0040 44da1b0029SMimi Zohar #define HASH 0x0100 45da1b0029SMimi Zohar #define DONT_HASH 0x0200 464af4662fSMimi Zohar 470260643cSEric Richter #define INVALID_PCR(a) (((a) < 0) || \ 480260643cSEric Richter (a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8)) 490260643cSEric Richter 50a756024eSRoberto Sassu int ima_policy_flag; 516ad6afa1SMimi Zohar static int temp_ima_appraise; 52ef96837bSMimi Zohar static int build_ima_appraise __ro_after_init; 53a756024eSRoberto Sassu 544af4662fSMimi Zohar #define MAX_LSM_RULES 6 554af4662fSMimi Zohar enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, 564af4662fSMimi Zohar LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE 574af4662fSMimi Zohar }; 583323eec9SMimi Zohar 5924fd03c8SMimi Zohar enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; 6024fd03c8SMimi Zohar 6107f6a794SMimi Zohar struct ima_rule_entry { 623323eec9SMimi Zohar struct list_head list; 632fe5d6deSMimi Zohar int action; 643323eec9SMimi Zohar unsigned int flags; 653323eec9SMimi Zohar enum ima_hooks func; 663323eec9SMimi Zohar int mask; 673323eec9SMimi Zohar unsigned long fsmagic; 68787d8c53SChristoph Hellwig uuid_t fsuuid; 698b94eea4SEric W. Biederman kuid_t uid; 7088265322SLinus Torvalds kuid_t fowner; 713dd0c8d0SMikhail Kurinnoi bool (*uid_op)(kuid_t, kuid_t); /* Handlers for operators */ 723dd0c8d0SMikhail Kurinnoi bool (*fowner_op)(kuid_t, kuid_t); /* uid_eq(), uid_gt(), uid_lt() */ 730260643cSEric Richter int pcr; 744af4662fSMimi Zohar struct { 754af4662fSMimi Zohar void *rule; /* LSM file metadata specific */ 767163a993SMimi Zohar void *args_p; /* audit value */ 774af4662fSMimi Zohar int type; /* audit type */ 784af4662fSMimi Zohar } lsm[MAX_LSM_RULES]; 79f1b08bbcSMimi Zohar char *fsname; 803323eec9SMimi Zohar }; 813323eec9SMimi Zohar 825789ba3bSEric Paris /* 835789ba3bSEric Paris * Without LSM specific knowledge, the default policy can only be 8407f6a794SMimi Zohar * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner 854af4662fSMimi Zohar */ 865789ba3bSEric Paris 875789ba3bSEric Paris /* 885789ba3bSEric Paris * The minimum rule set to allow for full TCB coverage. Measures all files 895789ba3bSEric Paris * opened or mmap for exec and everything read by root. Dangerous because 905789ba3bSEric Paris * normal users can easily run the machine out of memory simply building 915789ba3bSEric Paris * and running executables. 925789ba3bSEric Paris */ 93bad4417bSJames Morris static struct ima_rule_entry dont_measure_rules[] __ro_after_init = { 9475834fc3SEric Paris {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 953323eec9SMimi Zohar {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, 963323eec9SMimi Zohar {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, 973323eec9SMimi Zohar {.action = DONT_MEASURE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, 988445d64dSDmitry Kasatkin {.action = DONT_MEASURE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 998445d64dSDmitry Kasatkin {.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, 10075834fc3SEric Paris {.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, 10175834fc3SEric Paris {.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, 1021c070b18SMartin Townsend {.action = DONT_MEASURE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, 1036438de9fSRoberto Sassu {.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC, 1046438de9fSRoberto Sassu .flags = IMA_FSMAGIC}, 10582e3bb4dSLaura Abbott {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC, 10682e3bb4dSLaura Abbott .flags = IMA_FSMAGIC}, 10724fd03c8SMimi Zohar {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC} 10824fd03c8SMimi Zohar }; 10924fd03c8SMimi Zohar 110bad4417bSJames Morris static struct ima_rule_entry original_measurement_rules[] __ro_after_init = { 11116cac49fSMimi Zohar {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, 1123323eec9SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 1133323eec9SMimi Zohar {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, 1143323eec9SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 11524fd03c8SMimi Zohar {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 1163dd0c8d0SMikhail Kurinnoi .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, 1173dd0c8d0SMikhail Kurinnoi .flags = IMA_FUNC | IMA_MASK | IMA_UID}, 11824fd03c8SMimi Zohar {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, 11924fd03c8SMimi Zohar {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, 12024fd03c8SMimi Zohar }; 12124fd03c8SMimi Zohar 122bad4417bSJames Morris static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { 12324fd03c8SMimi Zohar {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, 12424fd03c8SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 12524fd03c8SMimi Zohar {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, 12624fd03c8SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 12724fd03c8SMimi Zohar {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 1283dd0c8d0SMikhail Kurinnoi .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, 1293dd0c8d0SMikhail Kurinnoi .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, 13024fd03c8SMimi Zohar {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 1313dd0c8d0SMikhail Kurinnoi .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, 1323dd0c8d0SMikhail Kurinnoi .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, 133fdf90729SMimi Zohar {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, 1345a9196d7SMimi Zohar {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, 13519f8a847SMimi Zohar {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, 1363323eec9SMimi Zohar }; 1373323eec9SMimi Zohar 138bad4417bSJames Morris static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { 13907f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 14007f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, 14107f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, 14207f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, 14307f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = RAMFS_MAGIC, .flags = IMA_FSMAGIC}, 14407f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 14507f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, 14607f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, 14707f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, 1481c070b18SMartin Townsend {.action = DONT_APPRAISE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, 149cd025f7fSMimi Zohar {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, 15007f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 15182e3bb4dSLaura Abbott {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 15295ee08faSMimi Zohar #ifdef CONFIG_IMA_WRITE_POLICY 15395ee08faSMimi Zohar {.action = APPRAISE, .func = POLICY_CHECK, 15495ee08faSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 15595ee08faSMimi Zohar #endif 156c57782c1SDmitry Kasatkin #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT 1573dd0c8d0SMikhail Kurinnoi {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, 1583dd0c8d0SMikhail Kurinnoi .flags = IMA_FOWNER}, 159c57782c1SDmitry Kasatkin #else 160c57782c1SDmitry Kasatkin /* force signature */ 1613dd0c8d0SMikhail Kurinnoi {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, 162c57782c1SDmitry Kasatkin .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, 163c57782c1SDmitry Kasatkin #endif 16407f6a794SMimi Zohar }; 1653323eec9SMimi Zohar 166ef96837bSMimi Zohar static struct ima_rule_entry build_appraise_rules[] __ro_after_init = { 167ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_MODULE_SIGS 168ef96837bSMimi Zohar {.action = APPRAISE, .func = MODULE_CHECK, 169ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 170ef96837bSMimi Zohar #endif 171ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_FIRMWARE_SIGS 172ef96837bSMimi Zohar {.action = APPRAISE, .func = FIRMWARE_CHECK, 173ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 174ef96837bSMimi Zohar #endif 175ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_KEXEC_SIGS 176ef96837bSMimi Zohar {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK, 177ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 178ef96837bSMimi Zohar #endif 179ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_POLICY_SIGS 180ef96837bSMimi Zohar {.action = APPRAISE, .func = POLICY_CHECK, 181ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 182ef96837bSMimi Zohar #endif 183ef96837bSMimi Zohar }; 184ef96837bSMimi Zohar 185503ceaefSMimi Zohar static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { 186503ceaefSMimi Zohar {.action = APPRAISE, .func = MODULE_CHECK, 187503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 188503ceaefSMimi Zohar {.action = APPRAISE, .func = FIRMWARE_CHECK, 189503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 190503ceaefSMimi Zohar {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK, 191503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 192503ceaefSMimi Zohar {.action = APPRAISE, .func = POLICY_CHECK, 193503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 194503ceaefSMimi Zohar }; 195503ceaefSMimi Zohar 19607f6a794SMimi Zohar static LIST_HEAD(ima_default_rules); 19707f6a794SMimi Zohar static LIST_HEAD(ima_policy_rules); 19838d859f9SPetko Manolov static LIST_HEAD(ima_temp_rules); 19907f6a794SMimi Zohar static struct list_head *ima_rules; 20007f6a794SMimi Zohar 20124fd03c8SMimi Zohar static int ima_policy __initdata; 20238d859f9SPetko Manolov 20307f6a794SMimi Zohar static int __init default_measure_policy_setup(char *str) 2045789ba3bSEric Paris { 20524fd03c8SMimi Zohar if (ima_policy) 20624fd03c8SMimi Zohar return 1; 20724fd03c8SMimi Zohar 20824fd03c8SMimi Zohar ima_policy = ORIGINAL_TCB; 2095789ba3bSEric Paris return 1; 2105789ba3bSEric Paris } 21107f6a794SMimi Zohar __setup("ima_tcb", default_measure_policy_setup); 21207f6a794SMimi Zohar 21333ce9549SMimi Zohar static bool ima_use_appraise_tcb __initdata; 214503ceaefSMimi Zohar static bool ima_use_secure_boot __initdata; 2159e67028eSMimi Zohar static bool ima_fail_unverifiable_sigs __ro_after_init; 21624fd03c8SMimi Zohar static int __init policy_setup(char *str) 21724fd03c8SMimi Zohar { 21833ce9549SMimi Zohar char *p; 21924fd03c8SMimi Zohar 22033ce9549SMimi Zohar while ((p = strsep(&str, " |\n")) != NULL) { 22133ce9549SMimi Zohar if (*p == ' ') 22233ce9549SMimi Zohar continue; 22333ce9549SMimi Zohar if ((strcmp(p, "tcb") == 0) && !ima_policy) 22424fd03c8SMimi Zohar ima_policy = DEFAULT_TCB; 22533ce9549SMimi Zohar else if (strcmp(p, "appraise_tcb") == 0) 22639adb925SThomas Meyer ima_use_appraise_tcb = true; 227503ceaefSMimi Zohar else if (strcmp(p, "secure_boot") == 0) 22839adb925SThomas Meyer ima_use_secure_boot = true; 2299e67028eSMimi Zohar else if (strcmp(p, "fail_securely") == 0) 2309e67028eSMimi Zohar ima_fail_unverifiable_sigs = true; 23133ce9549SMimi Zohar } 23224fd03c8SMimi Zohar 23324fd03c8SMimi Zohar return 1; 23424fd03c8SMimi Zohar } 23524fd03c8SMimi Zohar __setup("ima_policy=", policy_setup); 23624fd03c8SMimi Zohar 23707f6a794SMimi Zohar static int __init default_appraise_policy_setup(char *str) 23807f6a794SMimi Zohar { 23939adb925SThomas Meyer ima_use_appraise_tcb = true; 24007f6a794SMimi Zohar return 1; 24107f6a794SMimi Zohar } 24207f6a794SMimi Zohar __setup("ima_appraise_tcb", default_appraise_policy_setup); 2435789ba3bSEric Paris 2447163a993SMimi Zohar /* 24538d859f9SPetko Manolov * The LSM policy can be reloaded, leaving the IMA LSM based rules referring 24638d859f9SPetko Manolov * to the old, stale LSM policy. Update the IMA LSM based rules to reflect 24738d859f9SPetko Manolov * the reloaded LSM policy. We assume the rules still exist; and BUG_ON() if 24838d859f9SPetko Manolov * they don't. 2497163a993SMimi Zohar */ 2507163a993SMimi Zohar static void ima_lsm_update_rules(void) 2517163a993SMimi Zohar { 25238d859f9SPetko Manolov struct ima_rule_entry *entry; 2537163a993SMimi Zohar int result; 2547163a993SMimi Zohar int i; 2557163a993SMimi Zohar 25638d859f9SPetko Manolov list_for_each_entry(entry, &ima_policy_rules, list) { 2577163a993SMimi Zohar for (i = 0; i < MAX_LSM_RULES; i++) { 2587163a993SMimi Zohar if (!entry->lsm[i].rule) 2597163a993SMimi Zohar continue; 2607163a993SMimi Zohar result = security_filter_rule_init(entry->lsm[i].type, 2617163a993SMimi Zohar Audit_equal, 2627163a993SMimi Zohar entry->lsm[i].args_p, 2637163a993SMimi Zohar &entry->lsm[i].rule); 2647163a993SMimi Zohar BUG_ON(!entry->lsm[i].rule); 2657163a993SMimi Zohar } 2667163a993SMimi Zohar } 2677163a993SMimi Zohar } 2687163a993SMimi Zohar 2693323eec9SMimi Zohar /** 2703323eec9SMimi Zohar * ima_match_rules - determine whether an inode matches the measure rule. 2713323eec9SMimi Zohar * @rule: a pointer to a rule 2723323eec9SMimi Zohar * @inode: a pointer to an inode 273d906c10dSMatthew Garrett * @cred: a pointer to a credentials structure for user validation 274d906c10dSMatthew Garrett * @secid: the secid of the task to be validated 2753323eec9SMimi Zohar * @func: LIM hook identifier 2763323eec9SMimi Zohar * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) 2773323eec9SMimi Zohar * 2783323eec9SMimi Zohar * Returns true on rule match, false on failure. 2793323eec9SMimi Zohar */ 2804ad87a3dSMimi Zohar static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, 281d906c10dSMatthew Garrett const struct cred *cred, u32 secid, 2824ad87a3dSMimi Zohar enum ima_hooks func, int mask) 2833323eec9SMimi Zohar { 2844af4662fSMimi Zohar int i; 2853323eec9SMimi Zohar 28609b1148eSDmitry Kasatkin if ((rule->flags & IMA_FUNC) && 28709b1148eSDmitry Kasatkin (rule->func != func && func != POST_SETATTR)) 2883323eec9SMimi Zohar return false; 28909b1148eSDmitry Kasatkin if ((rule->flags & IMA_MASK) && 29009b1148eSDmitry Kasatkin (rule->mask != mask && func != POST_SETATTR)) 2913323eec9SMimi Zohar return false; 2924351c294SMimi Zohar if ((rule->flags & IMA_INMASK) && 2934351c294SMimi Zohar (!(rule->mask & mask) && func != POST_SETATTR)) 2944351c294SMimi Zohar return false; 2953323eec9SMimi Zohar if ((rule->flags & IMA_FSMAGIC) 2963323eec9SMimi Zohar && rule->fsmagic != inode->i_sb->s_magic) 2973323eec9SMimi Zohar return false; 298f1b08bbcSMimi Zohar if ((rule->flags & IMA_FSNAME) 299f1b08bbcSMimi Zohar && strcmp(rule->fsname, inode->i_sb->s_type->name)) 300f1b08bbcSMimi Zohar return false; 30185865c1fSDmitry Kasatkin if ((rule->flags & IMA_FSUUID) && 30285787090SChristoph Hellwig !uuid_equal(&rule->fsuuid, &inode->i_sb->s_uuid)) 30385865c1fSDmitry Kasatkin return false; 3043dd0c8d0SMikhail Kurinnoi if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid)) 3053323eec9SMimi Zohar return false; 306139069efSMimi Zohar if (rule->flags & IMA_EUID) { 307139069efSMimi Zohar if (has_capability_noaudit(current, CAP_SETUID)) { 3083dd0c8d0SMikhail Kurinnoi if (!rule->uid_op(cred->euid, rule->uid) 3093dd0c8d0SMikhail Kurinnoi && !rule->uid_op(cred->suid, rule->uid) 3103dd0c8d0SMikhail Kurinnoi && !rule->uid_op(cred->uid, rule->uid)) 311139069efSMimi Zohar return false; 3123dd0c8d0SMikhail Kurinnoi } else if (!rule->uid_op(cred->euid, rule->uid)) 313139069efSMimi Zohar return false; 314139069efSMimi Zohar } 315139069efSMimi Zohar 3163dd0c8d0SMikhail Kurinnoi if ((rule->flags & IMA_FOWNER) && 3173dd0c8d0SMikhail Kurinnoi !rule->fowner_op(inode->i_uid, rule->fowner)) 31807f6a794SMimi Zohar return false; 3194af4662fSMimi Zohar for (i = 0; i < MAX_LSM_RULES; i++) { 32053fc0e22SMimi Zohar int rc = 0; 321d906c10dSMatthew Garrett u32 osid; 3227163a993SMimi Zohar int retried = 0; 3234af4662fSMimi Zohar 3244af4662fSMimi Zohar if (!rule->lsm[i].rule) 3254af4662fSMimi Zohar continue; 3267163a993SMimi Zohar retry: 3274af4662fSMimi Zohar switch (i) { 3284af4662fSMimi Zohar case LSM_OBJ_USER: 3294af4662fSMimi Zohar case LSM_OBJ_ROLE: 3304af4662fSMimi Zohar case LSM_OBJ_TYPE: 3314af4662fSMimi Zohar security_inode_getsecid(inode, &osid); 3324af4662fSMimi Zohar rc = security_filter_rule_match(osid, 3334af4662fSMimi Zohar rule->lsm[i].type, 33453fc0e22SMimi Zohar Audit_equal, 3354af4662fSMimi Zohar rule->lsm[i].rule, 3364af4662fSMimi Zohar NULL); 3374af4662fSMimi Zohar break; 3384af4662fSMimi Zohar case LSM_SUBJ_USER: 3394af4662fSMimi Zohar case LSM_SUBJ_ROLE: 3404af4662fSMimi Zohar case LSM_SUBJ_TYPE: 341d906c10dSMatthew Garrett rc = security_filter_rule_match(secid, 3424af4662fSMimi Zohar rule->lsm[i].type, 34353fc0e22SMimi Zohar Audit_equal, 3444af4662fSMimi Zohar rule->lsm[i].rule, 3454af4662fSMimi Zohar NULL); 3464af4662fSMimi Zohar default: 3474af4662fSMimi Zohar break; 3484af4662fSMimi Zohar } 3497163a993SMimi Zohar if ((rc < 0) && (!retried)) { 3507163a993SMimi Zohar retried = 1; 3517163a993SMimi Zohar ima_lsm_update_rules(); 3527163a993SMimi Zohar goto retry; 3537163a993SMimi Zohar } 3544af4662fSMimi Zohar if (!rc) 3554af4662fSMimi Zohar return false; 3564af4662fSMimi Zohar } 3573323eec9SMimi Zohar return true; 3583323eec9SMimi Zohar } 3593323eec9SMimi Zohar 360d79d72e0SMimi Zohar /* 361d79d72e0SMimi Zohar * In addition to knowing that we need to appraise the file in general, 3625a73fcfaSMimi Zohar * we need to differentiate between calling hooks, for hook specific rules. 363d79d72e0SMimi Zohar */ 3644ad87a3dSMimi Zohar static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) 365d79d72e0SMimi Zohar { 3665a73fcfaSMimi Zohar if (!(rule->flags & IMA_FUNC)) 3675a73fcfaSMimi Zohar return IMA_FILE_APPRAISE; 3685a73fcfaSMimi Zohar 369d79d72e0SMimi Zohar switch (func) { 370d79d72e0SMimi Zohar case MMAP_CHECK: 371d79d72e0SMimi Zohar return IMA_MMAP_APPRAISE; 372d79d72e0SMimi Zohar case BPRM_CHECK: 373d79d72e0SMimi Zohar return IMA_BPRM_APPRAISE; 374d906c10dSMatthew Garrett case CREDS_CHECK: 375d906c10dSMatthew Garrett return IMA_CREDS_APPRAISE; 376d79d72e0SMimi Zohar case FILE_CHECK: 377c6af8efeSMimi Zohar case POST_SETATTR: 378d79d72e0SMimi Zohar return IMA_FILE_APPRAISE; 379c6af8efeSMimi Zohar case MODULE_CHECK ... MAX_CHECK - 1: 380c6af8efeSMimi Zohar default: 381c6af8efeSMimi Zohar return IMA_READ_APPRAISE; 382d79d72e0SMimi Zohar } 383d79d72e0SMimi Zohar } 384d79d72e0SMimi Zohar 3853323eec9SMimi Zohar /** 3863323eec9SMimi Zohar * ima_match_policy - decision based on LSM and other conditions 3873323eec9SMimi Zohar * @inode: pointer to an inode for which the policy decision is being made 388d906c10dSMatthew Garrett * @cred: pointer to a credentials structure for which the policy decision is 389d906c10dSMatthew Garrett * being made 390d906c10dSMatthew Garrett * @secid: LSM secid of the task to be validated 3913323eec9SMimi Zohar * @func: IMA hook identifier 3923323eec9SMimi Zohar * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) 393725de7faSEric Richter * @pcr: set the pcr to extend 3943323eec9SMimi Zohar * 3953323eec9SMimi Zohar * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) 3963323eec9SMimi Zohar * conditions. 3973323eec9SMimi Zohar * 39838d859f9SPetko Manolov * Since the IMA policy may be updated multiple times we need to lock the 39938d859f9SPetko Manolov * list when walking it. Reads are many orders of magnitude more numerous 40038d859f9SPetko Manolov * than writes so ima_match_policy() is classical RCU candidate. 4013323eec9SMimi Zohar */ 402d906c10dSMatthew Garrett int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, 403d906c10dSMatthew Garrett enum ima_hooks func, int mask, int flags, int *pcr) 4043323eec9SMimi Zohar { 40507f6a794SMimi Zohar struct ima_rule_entry *entry; 4062fe5d6deSMimi Zohar int action = 0, actmask = flags | (flags << 1); 4073323eec9SMimi Zohar 40838d859f9SPetko Manolov rcu_read_lock(); 40938d859f9SPetko Manolov list_for_each_entry_rcu(entry, ima_rules, list) { 4103323eec9SMimi Zohar 4112fe5d6deSMimi Zohar if (!(entry->action & actmask)) 4122fe5d6deSMimi Zohar continue; 4132fe5d6deSMimi Zohar 414d906c10dSMatthew Garrett if (!ima_match_rules(entry, inode, cred, secid, func, mask)) 4152fe5d6deSMimi Zohar continue; 4162fe5d6deSMimi Zohar 4170e5a247cSDmitry Kasatkin action |= entry->flags & IMA_ACTION_FLAGS; 4180e5a247cSDmitry Kasatkin 41945e2472eSDmitry Kasatkin action |= entry->action & IMA_DO_MASK; 420da1b0029SMimi Zohar if (entry->action & IMA_APPRAISE) { 4215a73fcfaSMimi Zohar action |= get_subaction(entry, func); 422a9a4935dSMimi Zohar action &= ~IMA_HASH; 4239e67028eSMimi Zohar if (ima_fail_unverifiable_sigs) 4249e67028eSMimi Zohar action |= IMA_FAIL_UNVERIFIABLE_SIGS; 425da1b0029SMimi Zohar } 426d79d72e0SMimi Zohar 42745e2472eSDmitry Kasatkin if (entry->action & IMA_DO_MASK) 42845e2472eSDmitry Kasatkin actmask &= ~(entry->action | entry->action << 1); 42945e2472eSDmitry Kasatkin else 43045e2472eSDmitry Kasatkin actmask &= ~(entry->action | entry->action >> 1); 43145e2472eSDmitry Kasatkin 432725de7faSEric Richter if ((pcr) && (entry->flags & IMA_PCR)) 433725de7faSEric Richter *pcr = entry->pcr; 434725de7faSEric Richter 4352fe5d6deSMimi Zohar if (!actmask) 4362fe5d6deSMimi Zohar break; 4373323eec9SMimi Zohar } 43838d859f9SPetko Manolov rcu_read_unlock(); 4392fe5d6deSMimi Zohar 4402fe5d6deSMimi Zohar return action; 4413323eec9SMimi Zohar } 4423323eec9SMimi Zohar 443a756024eSRoberto Sassu /* 444a756024eSRoberto Sassu * Initialize the ima_policy_flag variable based on the currently 445a756024eSRoberto Sassu * loaded policy. Based on this flag, the decision to short circuit 446a756024eSRoberto Sassu * out of a function or not call the function in the first place 447a756024eSRoberto Sassu * can be made earlier. 448a756024eSRoberto Sassu */ 449a756024eSRoberto Sassu void ima_update_policy_flag(void) 450a756024eSRoberto Sassu { 451a756024eSRoberto Sassu struct ima_rule_entry *entry; 452a756024eSRoberto Sassu 453a756024eSRoberto Sassu list_for_each_entry(entry, ima_rules, list) { 454a756024eSRoberto Sassu if (entry->action & IMA_DO_MASK) 455a756024eSRoberto Sassu ima_policy_flag |= entry->action; 456a756024eSRoberto Sassu } 457a756024eSRoberto Sassu 458ef96837bSMimi Zohar ima_appraise |= (build_ima_appraise | temp_ima_appraise); 459a756024eSRoberto Sassu if (!ima_appraise) 460a756024eSRoberto Sassu ima_policy_flag &= ~IMA_APPRAISE; 461a756024eSRoberto Sassu } 462a756024eSRoberto Sassu 4636f0911a6SMimi Zohar static int ima_appraise_flag(enum ima_hooks func) 4646f0911a6SMimi Zohar { 4656f0911a6SMimi Zohar if (func == MODULE_CHECK) 4666f0911a6SMimi Zohar return IMA_APPRAISE_MODULES; 4676f0911a6SMimi Zohar else if (func == FIRMWARE_CHECK) 4686f0911a6SMimi Zohar return IMA_APPRAISE_FIRMWARE; 4696f0911a6SMimi Zohar else if (func == POLICY_CHECK) 4706f0911a6SMimi Zohar return IMA_APPRAISE_POLICY; 47116c267aaSMimi Zohar else if (func == KEXEC_KERNEL_CHECK) 47216c267aaSMimi Zohar return IMA_APPRAISE_KEXEC; 4736f0911a6SMimi Zohar return 0; 4746f0911a6SMimi Zohar } 4756f0911a6SMimi Zohar 4763323eec9SMimi Zohar /** 4773323eec9SMimi Zohar * ima_init_policy - initialize the default measure rules. 4783323eec9SMimi Zohar * 47907f6a794SMimi Zohar * ima_rules points to either the ima_default_rules or the 48007f6a794SMimi Zohar * the new ima_policy_rules. 4813323eec9SMimi Zohar */ 482932995f0SEric Paris void __init ima_init_policy(void) 4833323eec9SMimi Zohar { 484503ceaefSMimi Zohar int i, measure_entries, appraise_entries, secure_boot_entries; 4853323eec9SMimi Zohar 48624fd03c8SMimi Zohar /* if !ima_policy set entries = 0 so we load NO default rules */ 48724fd03c8SMimi Zohar measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0; 48807f6a794SMimi Zohar appraise_entries = ima_use_appraise_tcb ? 48907f6a794SMimi Zohar ARRAY_SIZE(default_appraise_rules) : 0; 490503ceaefSMimi Zohar secure_boot_entries = ima_use_secure_boot ? 491503ceaefSMimi Zohar ARRAY_SIZE(secure_boot_rules) : 0; 4925789ba3bSEric Paris 4935577857fSDan Carpenter for (i = 0; i < measure_entries; i++) 49424fd03c8SMimi Zohar list_add_tail(&dont_measure_rules[i].list, &ima_default_rules); 49524fd03c8SMimi Zohar 49624fd03c8SMimi Zohar switch (ima_policy) { 49724fd03c8SMimi Zohar case ORIGINAL_TCB: 49824fd03c8SMimi Zohar for (i = 0; i < ARRAY_SIZE(original_measurement_rules); i++) 49924fd03c8SMimi Zohar list_add_tail(&original_measurement_rules[i].list, 50024fd03c8SMimi Zohar &ima_default_rules); 50124fd03c8SMimi Zohar break; 50224fd03c8SMimi Zohar case DEFAULT_TCB: 50324fd03c8SMimi Zohar for (i = 0; i < ARRAY_SIZE(default_measurement_rules); i++) 50424fd03c8SMimi Zohar list_add_tail(&default_measurement_rules[i].list, 50524fd03c8SMimi Zohar &ima_default_rules); 50624fd03c8SMimi Zohar default: 50724fd03c8SMimi Zohar break; 50824fd03c8SMimi Zohar } 50907f6a794SMimi Zohar 510503ceaefSMimi Zohar /* 511ef96837bSMimi Zohar * Insert the builtin "secure_boot" policy rules requiring file 512ef96837bSMimi Zohar * signatures, prior to any other appraise rules. 513503ceaefSMimi Zohar */ 5146f0911a6SMimi Zohar for (i = 0; i < secure_boot_entries; i++) { 5156f0911a6SMimi Zohar list_add_tail(&secure_boot_rules[i].list, &ima_default_rules); 5166f0911a6SMimi Zohar temp_ima_appraise |= 5176f0911a6SMimi Zohar ima_appraise_flag(secure_boot_rules[i].func); 5186f0911a6SMimi Zohar } 519503ceaefSMimi Zohar 520ef96837bSMimi Zohar /* 521ef96837bSMimi Zohar * Insert the build time appraise rules requiring file signatures 522ef96837bSMimi Zohar * for both the initial and custom policies, prior to other appraise 523ef96837bSMimi Zohar * rules. 524ef96837bSMimi Zohar */ 525ef96837bSMimi Zohar for (i = 0; i < ARRAY_SIZE(build_appraise_rules); i++) { 526ef96837bSMimi Zohar struct ima_rule_entry *entry; 527ef96837bSMimi Zohar 528ef96837bSMimi Zohar if (!secure_boot_entries) 529ef96837bSMimi Zohar list_add_tail(&build_appraise_rules[i].list, 530ef96837bSMimi Zohar &ima_default_rules); 531ef96837bSMimi Zohar 532ef96837bSMimi Zohar entry = kmemdup(&build_appraise_rules[i], sizeof(*entry), 533ef96837bSMimi Zohar GFP_KERNEL); 534ef96837bSMimi Zohar if (entry) 535ef96837bSMimi Zohar list_add_tail(&entry->list, &ima_policy_rules); 536ef96837bSMimi Zohar build_ima_appraise |= 537ef96837bSMimi Zohar ima_appraise_flag(build_appraise_rules[i].func); 538ef96837bSMimi Zohar } 539ef96837bSMimi Zohar 5405577857fSDan Carpenter for (i = 0; i < appraise_entries; i++) { 5415577857fSDan Carpenter list_add_tail(&default_appraise_rules[i].list, 54207f6a794SMimi Zohar &ima_default_rules); 54395ee08faSMimi Zohar if (default_appraise_rules[i].func == POLICY_CHECK) 54495ee08faSMimi Zohar temp_ima_appraise |= IMA_APPRAISE_POLICY; 54507f6a794SMimi Zohar } 54607f6a794SMimi Zohar 54707f6a794SMimi Zohar ima_rules = &ima_default_rules; 54895ee08faSMimi Zohar ima_update_policy_flag(); 5493323eec9SMimi Zohar } 5504af4662fSMimi Zohar 5510112721dSSasha Levin /* Make sure we have a valid policy, at least containing some rules. */ 552c75d8e96SColin Ian King int ima_check_policy(void) 5530112721dSSasha Levin { 5540112721dSSasha Levin if (list_empty(&ima_temp_rules)) 5550112721dSSasha Levin return -EINVAL; 5560112721dSSasha Levin return 0; 5570112721dSSasha Levin } 5580112721dSSasha Levin 5594af4662fSMimi Zohar /** 5604af4662fSMimi Zohar * ima_update_policy - update default_rules with new measure rules 5614af4662fSMimi Zohar * 5624af4662fSMimi Zohar * Called on file .release to update the default rules with a complete new 56338d859f9SPetko Manolov * policy. What we do here is to splice ima_policy_rules and ima_temp_rules so 56438d859f9SPetko Manolov * they make a queue. The policy may be updated multiple times and this is the 56538d859f9SPetko Manolov * RCU updater. 56638d859f9SPetko Manolov * 56738d859f9SPetko Manolov * Policy rules are never deleted so ima_policy_flag gets zeroed only once when 56838d859f9SPetko Manolov * we switch from the default policy to user defined. 5694af4662fSMimi Zohar */ 5704af4662fSMimi Zohar void ima_update_policy(void) 5714af4662fSMimi Zohar { 57253b626f9SPetko Manolov struct list_head *policy = &ima_policy_rules; 57338d859f9SPetko Manolov 57453b626f9SPetko Manolov list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu); 57538d859f9SPetko Manolov 57638d859f9SPetko Manolov if (ima_rules != policy) { 57738d859f9SPetko Manolov ima_policy_flag = 0; 57838d859f9SPetko Manolov ima_rules = policy; 57938d859f9SPetko Manolov } 580a756024eSRoberto Sassu ima_update_policy_flag(); 5814af4662fSMimi Zohar } 5824af4662fSMimi Zohar 5834af4662fSMimi Zohar enum { 5844af4662fSMimi Zohar Opt_err = -1, 5854af4662fSMimi Zohar Opt_measure = 1, Opt_dont_measure, 58607f6a794SMimi Zohar Opt_appraise, Opt_dont_appraise, 587da1b0029SMimi Zohar Opt_audit, Opt_hash, Opt_dont_hash, 5884af4662fSMimi Zohar Opt_obj_user, Opt_obj_role, Opt_obj_type, 5894af4662fSMimi Zohar Opt_subj_user, Opt_subj_role, Opt_subj_type, 590f1b08bbcSMimi Zohar Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname, 5913dd0c8d0SMikhail Kurinnoi Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq, 5923dd0c8d0SMikhail Kurinnoi Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, 5933dd0c8d0SMikhail Kurinnoi Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, 5940260643cSEric Richter Opt_appraise_type, Opt_permit_directio, 5950260643cSEric Richter Opt_pcr 5964af4662fSMimi Zohar }; 5974af4662fSMimi Zohar 5984af4662fSMimi Zohar static match_table_t policy_tokens = { 5994af4662fSMimi Zohar {Opt_measure, "measure"}, 6004af4662fSMimi Zohar {Opt_dont_measure, "dont_measure"}, 60107f6a794SMimi Zohar {Opt_appraise, "appraise"}, 60207f6a794SMimi Zohar {Opt_dont_appraise, "dont_appraise"}, 603e7c568e0SPeter Moody {Opt_audit, "audit"}, 604da1b0029SMimi Zohar {Opt_hash, "hash"}, 605da1b0029SMimi Zohar {Opt_dont_hash, "dont_hash"}, 6064af4662fSMimi Zohar {Opt_obj_user, "obj_user=%s"}, 6074af4662fSMimi Zohar {Opt_obj_role, "obj_role=%s"}, 6084af4662fSMimi Zohar {Opt_obj_type, "obj_type=%s"}, 6094af4662fSMimi Zohar {Opt_subj_user, "subj_user=%s"}, 6104af4662fSMimi Zohar {Opt_subj_role, "subj_role=%s"}, 6114af4662fSMimi Zohar {Opt_subj_type, "subj_type=%s"}, 6124af4662fSMimi Zohar {Opt_func, "func=%s"}, 6134af4662fSMimi Zohar {Opt_mask, "mask=%s"}, 6144af4662fSMimi Zohar {Opt_fsmagic, "fsmagic=%s"}, 615f1b08bbcSMimi Zohar {Opt_fsname, "fsname=%s"}, 61685865c1fSDmitry Kasatkin {Opt_fsuuid, "fsuuid=%s"}, 6173dd0c8d0SMikhail Kurinnoi {Opt_uid_eq, "uid=%s"}, 6183dd0c8d0SMikhail Kurinnoi {Opt_euid_eq, "euid=%s"}, 6193dd0c8d0SMikhail Kurinnoi {Opt_fowner_eq, "fowner=%s"}, 6203dd0c8d0SMikhail Kurinnoi {Opt_uid_gt, "uid>%s"}, 6213dd0c8d0SMikhail Kurinnoi {Opt_euid_gt, "euid>%s"}, 6223dd0c8d0SMikhail Kurinnoi {Opt_fowner_gt, "fowner>%s"}, 6233dd0c8d0SMikhail Kurinnoi {Opt_uid_lt, "uid<%s"}, 6243dd0c8d0SMikhail Kurinnoi {Opt_euid_lt, "euid<%s"}, 6253dd0c8d0SMikhail Kurinnoi {Opt_fowner_lt, "fowner<%s"}, 6260e5a247cSDmitry Kasatkin {Opt_appraise_type, "appraise_type=%s"}, 627f9b2a735SMimi Zohar {Opt_permit_directio, "permit_directio"}, 6280260643cSEric Richter {Opt_pcr, "pcr=%s"}, 6294af4662fSMimi Zohar {Opt_err, NULL} 6304af4662fSMimi Zohar }; 6314af4662fSMimi Zohar 63207f6a794SMimi Zohar static int ima_lsm_rule_init(struct ima_rule_entry *entry, 6337163a993SMimi Zohar substring_t *args, int lsm_rule, int audit_type) 6344af4662fSMimi Zohar { 6354af4662fSMimi Zohar int result; 6364af4662fSMimi Zohar 6377b62e162SEric Paris if (entry->lsm[lsm_rule].rule) 6387b62e162SEric Paris return -EINVAL; 6397b62e162SEric Paris 6407163a993SMimi Zohar entry->lsm[lsm_rule].args_p = match_strdup(args); 6417163a993SMimi Zohar if (!entry->lsm[lsm_rule].args_p) 6427163a993SMimi Zohar return -ENOMEM; 6437163a993SMimi Zohar 6444af4662fSMimi Zohar entry->lsm[lsm_rule].type = audit_type; 6454af4662fSMimi Zohar result = security_filter_rule_init(entry->lsm[lsm_rule].type, 6467163a993SMimi Zohar Audit_equal, 6477163a993SMimi Zohar entry->lsm[lsm_rule].args_p, 6484af4662fSMimi Zohar &entry->lsm[lsm_rule].rule); 6497163a993SMimi Zohar if (!entry->lsm[lsm_rule].rule) { 6507163a993SMimi Zohar kfree(entry->lsm[lsm_rule].args_p); 651867c2026SMimi Zohar return -EINVAL; 6527163a993SMimi Zohar } 6537163a993SMimi Zohar 6544af4662fSMimi Zohar return result; 6554af4662fSMimi Zohar } 6564af4662fSMimi Zohar 6573dd0c8d0SMikhail Kurinnoi static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value, 6583dd0c8d0SMikhail Kurinnoi bool (*rule_operator)(kuid_t, kuid_t)) 6592f1506cdSEric Paris { 660*2afd020aSStefan Berger if (!ab) 661*2afd020aSStefan Berger return; 662*2afd020aSStefan Berger 6633dd0c8d0SMikhail Kurinnoi if (rule_operator == &uid_gt) 6643dd0c8d0SMikhail Kurinnoi audit_log_format(ab, "%s>", key); 6653dd0c8d0SMikhail Kurinnoi else if (rule_operator == &uid_lt) 6663dd0c8d0SMikhail Kurinnoi audit_log_format(ab, "%s<", key); 6673dd0c8d0SMikhail Kurinnoi else 6682f1506cdSEric Paris audit_log_format(ab, "%s=", key); 6693d2859d5SStefan Berger audit_log_format(ab, "%s ", value); 6702f1506cdSEric Paris } 6713dd0c8d0SMikhail Kurinnoi static void ima_log_string(struct audit_buffer *ab, char *key, char *value) 6723dd0c8d0SMikhail Kurinnoi { 6733dd0c8d0SMikhail Kurinnoi ima_log_string_op(ab, key, value, NULL); 6743dd0c8d0SMikhail Kurinnoi } 6752f1506cdSEric Paris 67607f6a794SMimi Zohar static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) 6774af4662fSMimi Zohar { 6784af4662fSMimi Zohar struct audit_buffer *ab; 6794351c294SMimi Zohar char *from; 6804af4662fSMimi Zohar char *p; 6813dd0c8d0SMikhail Kurinnoi bool uid_token; 6824af4662fSMimi Zohar int result = 0; 6834af4662fSMimi Zohar 684*2afd020aSStefan Berger ab = integrity_audit_log_start(NULL, GFP_KERNEL, 685*2afd020aSStefan Berger AUDIT_INTEGRITY_RULE); 6864af4662fSMimi Zohar 6878b94eea4SEric W. Biederman entry->uid = INVALID_UID; 68888265322SLinus Torvalds entry->fowner = INVALID_UID; 6893dd0c8d0SMikhail Kurinnoi entry->uid_op = &uid_eq; 6903dd0c8d0SMikhail Kurinnoi entry->fowner_op = &uid_eq; 691b9035b1fSEric Paris entry->action = UNKNOWN; 69228ef4002SEric Paris while ((p = strsep(&rule, " \t")) != NULL) { 6934af4662fSMimi Zohar substring_t args[MAX_OPT_ARGS]; 6944af4662fSMimi Zohar int token; 6954af4662fSMimi Zohar unsigned long lnum; 6964af4662fSMimi Zohar 6974af4662fSMimi Zohar if (result < 0) 6984af4662fSMimi Zohar break; 69928ef4002SEric Paris if ((*p == '\0') || (*p == ' ') || (*p == '\t')) 70028ef4002SEric Paris continue; 7014af4662fSMimi Zohar token = match_token(p, policy_tokens, args); 7024af4662fSMimi Zohar switch (token) { 7034af4662fSMimi Zohar case Opt_measure: 7042f1506cdSEric Paris ima_log_string(ab, "action", "measure"); 7057b62e162SEric Paris 7067b62e162SEric Paris if (entry->action != UNKNOWN) 7077b62e162SEric Paris result = -EINVAL; 7087b62e162SEric Paris 7094af4662fSMimi Zohar entry->action = MEASURE; 7104af4662fSMimi Zohar break; 7114af4662fSMimi Zohar case Opt_dont_measure: 7122f1506cdSEric Paris ima_log_string(ab, "action", "dont_measure"); 7137b62e162SEric Paris 7147b62e162SEric Paris if (entry->action != UNKNOWN) 7157b62e162SEric Paris result = -EINVAL; 7167b62e162SEric Paris 7174af4662fSMimi Zohar entry->action = DONT_MEASURE; 7184af4662fSMimi Zohar break; 71907f6a794SMimi Zohar case Opt_appraise: 72007f6a794SMimi Zohar ima_log_string(ab, "action", "appraise"); 72107f6a794SMimi Zohar 72207f6a794SMimi Zohar if (entry->action != UNKNOWN) 72307f6a794SMimi Zohar result = -EINVAL; 72407f6a794SMimi Zohar 72507f6a794SMimi Zohar entry->action = APPRAISE; 72607f6a794SMimi Zohar break; 72707f6a794SMimi Zohar case Opt_dont_appraise: 72807f6a794SMimi Zohar ima_log_string(ab, "action", "dont_appraise"); 72907f6a794SMimi Zohar 73007f6a794SMimi Zohar if (entry->action != UNKNOWN) 73107f6a794SMimi Zohar result = -EINVAL; 73207f6a794SMimi Zohar 73307f6a794SMimi Zohar entry->action = DONT_APPRAISE; 73407f6a794SMimi Zohar break; 735e7c568e0SPeter Moody case Opt_audit: 736e7c568e0SPeter Moody ima_log_string(ab, "action", "audit"); 737e7c568e0SPeter Moody 738e7c568e0SPeter Moody if (entry->action != UNKNOWN) 739e7c568e0SPeter Moody result = -EINVAL; 740e7c568e0SPeter Moody 741e7c568e0SPeter Moody entry->action = AUDIT; 742e7c568e0SPeter Moody break; 743da1b0029SMimi Zohar case Opt_hash: 744da1b0029SMimi Zohar ima_log_string(ab, "action", "hash"); 745da1b0029SMimi Zohar 746da1b0029SMimi Zohar if (entry->action != UNKNOWN) 747da1b0029SMimi Zohar result = -EINVAL; 748da1b0029SMimi Zohar 749da1b0029SMimi Zohar entry->action = HASH; 750da1b0029SMimi Zohar break; 751da1b0029SMimi Zohar case Opt_dont_hash: 752da1b0029SMimi Zohar ima_log_string(ab, "action", "dont_hash"); 753da1b0029SMimi Zohar 754da1b0029SMimi Zohar if (entry->action != UNKNOWN) 755da1b0029SMimi Zohar result = -EINVAL; 756da1b0029SMimi Zohar 757da1b0029SMimi Zohar entry->action = DONT_HASH; 758da1b0029SMimi Zohar break; 7594af4662fSMimi Zohar case Opt_func: 7602f1506cdSEric Paris ima_log_string(ab, "func", args[0].from); 7617b62e162SEric Paris 7627b62e162SEric Paris if (entry->func) 7637b62e162SEric Paris result = -EINVAL; 7647b62e162SEric Paris 7651e93d005SMimi Zohar if (strcmp(args[0].from, "FILE_CHECK") == 0) 7661e93d005SMimi Zohar entry->func = FILE_CHECK; 7671e93d005SMimi Zohar /* PATH_CHECK is for backwards compat */ 7681e93d005SMimi Zohar else if (strcmp(args[0].from, "PATH_CHECK") == 0) 7691e93d005SMimi Zohar entry->func = FILE_CHECK; 770fdf90729SMimi Zohar else if (strcmp(args[0].from, "MODULE_CHECK") == 0) 771fdf90729SMimi Zohar entry->func = MODULE_CHECK; 7725a9196d7SMimi Zohar else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0) 7735a9196d7SMimi Zohar entry->func = FIRMWARE_CHECK; 77416cac49fSMimi Zohar else if ((strcmp(args[0].from, "FILE_MMAP") == 0) 77516cac49fSMimi Zohar || (strcmp(args[0].from, "MMAP_CHECK") == 0)) 77616cac49fSMimi Zohar entry->func = MMAP_CHECK; 7774af4662fSMimi Zohar else if (strcmp(args[0].from, "BPRM_CHECK") == 0) 7784af4662fSMimi Zohar entry->func = BPRM_CHECK; 779d906c10dSMatthew Garrett else if (strcmp(args[0].from, "CREDS_CHECK") == 0) 780d906c10dSMatthew Garrett entry->func = CREDS_CHECK; 781d9ddf077SMimi Zohar else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") == 782d9ddf077SMimi Zohar 0) 783d9ddf077SMimi Zohar entry->func = KEXEC_KERNEL_CHECK; 784d9ddf077SMimi Zohar else if (strcmp(args[0].from, "KEXEC_INITRAMFS_CHECK") 785d9ddf077SMimi Zohar == 0) 786d9ddf077SMimi Zohar entry->func = KEXEC_INITRAMFS_CHECK; 78719f8a847SMimi Zohar else if (strcmp(args[0].from, "POLICY_CHECK") == 0) 78819f8a847SMimi Zohar entry->func = POLICY_CHECK; 7894af4662fSMimi Zohar else 7904af4662fSMimi Zohar result = -EINVAL; 7914af4662fSMimi Zohar if (!result) 7924af4662fSMimi Zohar entry->flags |= IMA_FUNC; 7934af4662fSMimi Zohar break; 7944af4662fSMimi Zohar case Opt_mask: 7952f1506cdSEric Paris ima_log_string(ab, "mask", args[0].from); 7967b62e162SEric Paris 7977b62e162SEric Paris if (entry->mask) 7987b62e162SEric Paris result = -EINVAL; 7997b62e162SEric Paris 8004351c294SMimi Zohar from = args[0].from; 8014351c294SMimi Zohar if (*from == '^') 8024351c294SMimi Zohar from++; 8034351c294SMimi Zohar 8044351c294SMimi Zohar if ((strcmp(from, "MAY_EXEC")) == 0) 8054af4662fSMimi Zohar entry->mask = MAY_EXEC; 8064351c294SMimi Zohar else if (strcmp(from, "MAY_WRITE") == 0) 8074af4662fSMimi Zohar entry->mask = MAY_WRITE; 8084351c294SMimi Zohar else if (strcmp(from, "MAY_READ") == 0) 8094af4662fSMimi Zohar entry->mask = MAY_READ; 8104351c294SMimi Zohar else if (strcmp(from, "MAY_APPEND") == 0) 8114af4662fSMimi Zohar entry->mask = MAY_APPEND; 8124af4662fSMimi Zohar else 8134af4662fSMimi Zohar result = -EINVAL; 8144af4662fSMimi Zohar if (!result) 8154351c294SMimi Zohar entry->flags |= (*args[0].from == '^') 8164351c294SMimi Zohar ? IMA_INMASK : IMA_MASK; 8174af4662fSMimi Zohar break; 8184af4662fSMimi Zohar case Opt_fsmagic: 8192f1506cdSEric Paris ima_log_string(ab, "fsmagic", args[0].from); 8207b62e162SEric Paris 8217b62e162SEric Paris if (entry->fsmagic) { 8227b62e162SEric Paris result = -EINVAL; 8237b62e162SEric Paris break; 8247b62e162SEric Paris } 8257b62e162SEric Paris 8262bb930abSDmitry Kasatkin result = kstrtoul(args[0].from, 16, &entry->fsmagic); 8274af4662fSMimi Zohar if (!result) 8284af4662fSMimi Zohar entry->flags |= IMA_FSMAGIC; 8294af4662fSMimi Zohar break; 830f1b08bbcSMimi Zohar case Opt_fsname: 831f1b08bbcSMimi Zohar ima_log_string(ab, "fsname", args[0].from); 832f1b08bbcSMimi Zohar 833f1b08bbcSMimi Zohar entry->fsname = kstrdup(args[0].from, GFP_KERNEL); 834f1b08bbcSMimi Zohar if (!entry->fsname) { 835f1b08bbcSMimi Zohar result = -ENOMEM; 836f1b08bbcSMimi Zohar break; 837f1b08bbcSMimi Zohar } 838f1b08bbcSMimi Zohar result = 0; 839f1b08bbcSMimi Zohar entry->flags |= IMA_FSNAME; 840f1b08bbcSMimi Zohar break; 84185865c1fSDmitry Kasatkin case Opt_fsuuid: 84285865c1fSDmitry Kasatkin ima_log_string(ab, "fsuuid", args[0].from); 84385865c1fSDmitry Kasatkin 84436447456SMike Rapoport if (!uuid_is_null(&entry->fsuuid)) { 84585865c1fSDmitry Kasatkin result = -EINVAL; 84685865c1fSDmitry Kasatkin break; 84785865c1fSDmitry Kasatkin } 84885865c1fSDmitry Kasatkin 849787d8c53SChristoph Hellwig result = uuid_parse(args[0].from, &entry->fsuuid); 850446d64e3SMimi Zohar if (!result) 85185865c1fSDmitry Kasatkin entry->flags |= IMA_FSUUID; 85285865c1fSDmitry Kasatkin break; 8533dd0c8d0SMikhail Kurinnoi case Opt_uid_gt: 8543dd0c8d0SMikhail Kurinnoi case Opt_euid_gt: 8553dd0c8d0SMikhail Kurinnoi entry->uid_op = &uid_gt; 8563dd0c8d0SMikhail Kurinnoi case Opt_uid_lt: 8573dd0c8d0SMikhail Kurinnoi case Opt_euid_lt: 8583dd0c8d0SMikhail Kurinnoi if ((token == Opt_uid_lt) || (token == Opt_euid_lt)) 8593dd0c8d0SMikhail Kurinnoi entry->uid_op = &uid_lt; 8603dd0c8d0SMikhail Kurinnoi case Opt_uid_eq: 8613dd0c8d0SMikhail Kurinnoi case Opt_euid_eq: 8623dd0c8d0SMikhail Kurinnoi uid_token = (token == Opt_uid_eq) || 8633dd0c8d0SMikhail Kurinnoi (token == Opt_uid_gt) || 8643dd0c8d0SMikhail Kurinnoi (token == Opt_uid_lt); 8653dd0c8d0SMikhail Kurinnoi 8663dd0c8d0SMikhail Kurinnoi ima_log_string_op(ab, uid_token ? "uid" : "euid", 8673dd0c8d0SMikhail Kurinnoi args[0].from, entry->uid_op); 8687b62e162SEric Paris 8698b94eea4SEric W. Biederman if (uid_valid(entry->uid)) { 8707b62e162SEric Paris result = -EINVAL; 8717b62e162SEric Paris break; 8727b62e162SEric Paris } 8737b62e162SEric Paris 87429707b20SJingoo Han result = kstrtoul(args[0].from, 10, &lnum); 8754af4662fSMimi Zohar if (!result) { 876139069efSMimi Zohar entry->uid = make_kuid(current_user_ns(), 877139069efSMimi Zohar (uid_t) lnum); 878139069efSMimi Zohar if (!uid_valid(entry->uid) || 879139069efSMimi Zohar (uid_t)lnum != lnum) 8804af4662fSMimi Zohar result = -EINVAL; 8814af4662fSMimi Zohar else 8823dd0c8d0SMikhail Kurinnoi entry->flags |= uid_token 883139069efSMimi Zohar ? IMA_UID : IMA_EUID; 8844af4662fSMimi Zohar } 8854af4662fSMimi Zohar break; 8863dd0c8d0SMikhail Kurinnoi case Opt_fowner_gt: 8873dd0c8d0SMikhail Kurinnoi entry->fowner_op = &uid_gt; 8883dd0c8d0SMikhail Kurinnoi case Opt_fowner_lt: 8893dd0c8d0SMikhail Kurinnoi if (token == Opt_fowner_lt) 8903dd0c8d0SMikhail Kurinnoi entry->fowner_op = &uid_lt; 8913dd0c8d0SMikhail Kurinnoi case Opt_fowner_eq: 8923dd0c8d0SMikhail Kurinnoi ima_log_string_op(ab, "fowner", args[0].from, 8933dd0c8d0SMikhail Kurinnoi entry->fowner_op); 89407f6a794SMimi Zohar 89588265322SLinus Torvalds if (uid_valid(entry->fowner)) { 89607f6a794SMimi Zohar result = -EINVAL; 89707f6a794SMimi Zohar break; 89807f6a794SMimi Zohar } 89907f6a794SMimi Zohar 90029707b20SJingoo Han result = kstrtoul(args[0].from, 10, &lnum); 90107f6a794SMimi Zohar if (!result) { 90288265322SLinus Torvalds entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum); 90388265322SLinus Torvalds if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum)) 90407f6a794SMimi Zohar result = -EINVAL; 90507f6a794SMimi Zohar else 90607f6a794SMimi Zohar entry->flags |= IMA_FOWNER; 90707f6a794SMimi Zohar } 90807f6a794SMimi Zohar break; 9094af4662fSMimi Zohar case Opt_obj_user: 9102f1506cdSEric Paris ima_log_string(ab, "obj_user", args[0].from); 9117163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 9124af4662fSMimi Zohar LSM_OBJ_USER, 9134af4662fSMimi Zohar AUDIT_OBJ_USER); 9144af4662fSMimi Zohar break; 9154af4662fSMimi Zohar case Opt_obj_role: 9162f1506cdSEric Paris ima_log_string(ab, "obj_role", args[0].from); 9177163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 9184af4662fSMimi Zohar LSM_OBJ_ROLE, 9194af4662fSMimi Zohar AUDIT_OBJ_ROLE); 9204af4662fSMimi Zohar break; 9214af4662fSMimi Zohar case Opt_obj_type: 9222f1506cdSEric Paris ima_log_string(ab, "obj_type", args[0].from); 9237163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 9244af4662fSMimi Zohar LSM_OBJ_TYPE, 9254af4662fSMimi Zohar AUDIT_OBJ_TYPE); 9264af4662fSMimi Zohar break; 9274af4662fSMimi Zohar case Opt_subj_user: 9282f1506cdSEric Paris ima_log_string(ab, "subj_user", args[0].from); 9297163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 9304af4662fSMimi Zohar LSM_SUBJ_USER, 9314af4662fSMimi Zohar AUDIT_SUBJ_USER); 9324af4662fSMimi Zohar break; 9334af4662fSMimi Zohar case Opt_subj_role: 9342f1506cdSEric Paris ima_log_string(ab, "subj_role", args[0].from); 9357163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 9364af4662fSMimi Zohar LSM_SUBJ_ROLE, 9374af4662fSMimi Zohar AUDIT_SUBJ_ROLE); 9384af4662fSMimi Zohar break; 9394af4662fSMimi Zohar case Opt_subj_type: 9402f1506cdSEric Paris ima_log_string(ab, "subj_type", args[0].from); 9417163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 9424af4662fSMimi Zohar LSM_SUBJ_TYPE, 9434af4662fSMimi Zohar AUDIT_SUBJ_TYPE); 9444af4662fSMimi Zohar break; 9450e5a247cSDmitry Kasatkin case Opt_appraise_type: 9460e5a247cSDmitry Kasatkin if (entry->action != APPRAISE) { 9470e5a247cSDmitry Kasatkin result = -EINVAL; 9480e5a247cSDmitry Kasatkin break; 9490e5a247cSDmitry Kasatkin } 9500e5a247cSDmitry Kasatkin 9510e5a247cSDmitry Kasatkin ima_log_string(ab, "appraise_type", args[0].from); 9520e5a247cSDmitry Kasatkin if ((strcmp(args[0].from, "imasig")) == 0) 9530e5a247cSDmitry Kasatkin entry->flags |= IMA_DIGSIG_REQUIRED; 9540e5a247cSDmitry Kasatkin else 9550e5a247cSDmitry Kasatkin result = -EINVAL; 9560e5a247cSDmitry Kasatkin break; 957f9b2a735SMimi Zohar case Opt_permit_directio: 958f9b2a735SMimi Zohar entry->flags |= IMA_PERMIT_DIRECTIO; 959f9b2a735SMimi Zohar break; 9600260643cSEric Richter case Opt_pcr: 9610260643cSEric Richter if (entry->action != MEASURE) { 9620260643cSEric Richter result = -EINVAL; 9630260643cSEric Richter break; 9640260643cSEric Richter } 9650260643cSEric Richter ima_log_string(ab, "pcr", args[0].from); 9660260643cSEric Richter 9670260643cSEric Richter result = kstrtoint(args[0].from, 10, &entry->pcr); 9680260643cSEric Richter if (result || INVALID_PCR(entry->pcr)) 9690260643cSEric Richter result = -EINVAL; 9700260643cSEric Richter else 9710260643cSEric Richter entry->flags |= IMA_PCR; 9720260643cSEric Richter 9730260643cSEric Richter break; 9744af4662fSMimi Zohar case Opt_err: 9752f1506cdSEric Paris ima_log_string(ab, "UNKNOWN", p); 976e9d393bfSEric Paris result = -EINVAL; 9774af4662fSMimi Zohar break; 9784af4662fSMimi Zohar } 9794af4662fSMimi Zohar } 9807b62e162SEric Paris if (!result && (entry->action == UNKNOWN)) 9814af4662fSMimi Zohar result = -EINVAL; 9826f0911a6SMimi Zohar else if (entry->action == APPRAISE) 9836f0911a6SMimi Zohar temp_ima_appraise |= ima_appraise_flag(entry->func); 9846f0911a6SMimi Zohar 985b0d5de4dSEric Paris audit_log_format(ab, "res=%d", !result); 9864af4662fSMimi Zohar audit_log_end(ab); 9874af4662fSMimi Zohar return result; 9884af4662fSMimi Zohar } 9894af4662fSMimi Zohar 9904af4662fSMimi Zohar /** 99107f6a794SMimi Zohar * ima_parse_add_rule - add a rule to ima_policy_rules 9924af4662fSMimi Zohar * @rule - ima measurement policy rule 9934af4662fSMimi Zohar * 99438d859f9SPetko Manolov * Avoid locking by allowing just one writer at a time in ima_write_policy() 9956ccd0456SEric Paris * Returns the length of the rule parsed, an error code on failure 9964af4662fSMimi Zohar */ 9976ccd0456SEric Paris ssize_t ima_parse_add_rule(char *rule) 9984af4662fSMimi Zohar { 99952a13284SMimi Zohar static const char op[] = "update_policy"; 10006ccd0456SEric Paris char *p; 100107f6a794SMimi Zohar struct ima_rule_entry *entry; 10026ccd0456SEric Paris ssize_t result, len; 10034af4662fSMimi Zohar int audit_info = 0; 10044af4662fSMimi Zohar 1005272a6e90SDmitry Kasatkin p = strsep(&rule, "\n"); 1006272a6e90SDmitry Kasatkin len = strlen(p) + 1; 10077178784fSDmitry Kasatkin p += strspn(p, " \t"); 1008272a6e90SDmitry Kasatkin 10097178784fSDmitry Kasatkin if (*p == '#' || *p == '\0') 1010272a6e90SDmitry Kasatkin return len; 1011272a6e90SDmitry Kasatkin 10124af4662fSMimi Zohar entry = kzalloc(sizeof(*entry), GFP_KERNEL); 10134af4662fSMimi Zohar if (!entry) { 10144af4662fSMimi Zohar integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 10154af4662fSMimi Zohar NULL, op, "-ENOMEM", -ENOMEM, audit_info); 10164af4662fSMimi Zohar return -ENOMEM; 10174af4662fSMimi Zohar } 10184af4662fSMimi Zohar 10194af4662fSMimi Zohar INIT_LIST_HEAD(&entry->list); 10204af4662fSMimi Zohar 10216ccd0456SEric Paris result = ima_parse_rule(p, entry); 10227233e3eeSEric Paris if (result) { 10234af4662fSMimi Zohar kfree(entry); 1024523979adSMimi Zohar integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 10257e9001f6SRichard Guy Briggs NULL, op, "invalid-policy", result, 1026523979adSMimi Zohar audit_info); 10274af4662fSMimi Zohar return result; 10284af4662fSMimi Zohar } 10294af4662fSMimi Zohar 103038d859f9SPetko Manolov list_add_tail(&entry->list, &ima_temp_rules); 10317233e3eeSEric Paris 10327233e3eeSEric Paris return len; 10337233e3eeSEric Paris } 10347233e3eeSEric Paris 103538d859f9SPetko Manolov /** 103638d859f9SPetko Manolov * ima_delete_rules() called to cleanup invalid in-flight policy. 103738d859f9SPetko Manolov * We don't need locking as we operate on the temp list, which is 103838d859f9SPetko Manolov * different from the active one. There is also only one user of 103938d859f9SPetko Manolov * ima_delete_rules() at a time. 104038d859f9SPetko Manolov */ 104164c61d80SJames Morris void ima_delete_rules(void) 10424af4662fSMimi Zohar { 104307f6a794SMimi Zohar struct ima_rule_entry *entry, *tmp; 10447163a993SMimi Zohar int i; 10454af4662fSMimi Zohar 10466ad6afa1SMimi Zohar temp_ima_appraise = 0; 104738d859f9SPetko Manolov list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) { 10487163a993SMimi Zohar for (i = 0; i < MAX_LSM_RULES; i++) 10497163a993SMimi Zohar kfree(entry->lsm[i].args_p); 10507163a993SMimi Zohar 10514af4662fSMimi Zohar list_del(&entry->list); 10524af4662fSMimi Zohar kfree(entry); 10534af4662fSMimi Zohar } 10544af4662fSMimi Zohar } 105580eae209SPetko Manolov 105680eae209SPetko Manolov #ifdef CONFIG_IMA_READ_POLICY 105780eae209SPetko Manolov enum { 105880eae209SPetko Manolov mask_exec = 0, mask_write, mask_read, mask_append 105980eae209SPetko Manolov }; 106080eae209SPetko Manolov 1061bb543e39SThiago Jung Bauermann static const char *const mask_tokens[] = { 106280eae209SPetko Manolov "MAY_EXEC", 106380eae209SPetko Manolov "MAY_WRITE", 106480eae209SPetko Manolov "MAY_READ", 106580eae209SPetko Manolov "MAY_APPEND" 106680eae209SPetko Manolov }; 106780eae209SPetko Manolov 10682663218bSThiago Jung Bauermann #define __ima_hook_stringify(str) (#str), 106980eae209SPetko Manolov 1070bb543e39SThiago Jung Bauermann static const char *const func_tokens[] = { 10712663218bSThiago Jung Bauermann __ima_hooks(__ima_hook_stringify) 107280eae209SPetko Manolov }; 107380eae209SPetko Manolov 107480eae209SPetko Manolov void *ima_policy_start(struct seq_file *m, loff_t *pos) 107580eae209SPetko Manolov { 107680eae209SPetko Manolov loff_t l = *pos; 107780eae209SPetko Manolov struct ima_rule_entry *entry; 107880eae209SPetko Manolov 107980eae209SPetko Manolov rcu_read_lock(); 108080eae209SPetko Manolov list_for_each_entry_rcu(entry, ima_rules, list) { 108180eae209SPetko Manolov if (!l--) { 108280eae209SPetko Manolov rcu_read_unlock(); 108380eae209SPetko Manolov return entry; 108480eae209SPetko Manolov } 108580eae209SPetko Manolov } 108680eae209SPetko Manolov rcu_read_unlock(); 108780eae209SPetko Manolov return NULL; 108880eae209SPetko Manolov } 108980eae209SPetko Manolov 109080eae209SPetko Manolov void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) 109180eae209SPetko Manolov { 109280eae209SPetko Manolov struct ima_rule_entry *entry = v; 109380eae209SPetko Manolov 109480eae209SPetko Manolov rcu_read_lock(); 109580eae209SPetko Manolov entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list); 109680eae209SPetko Manolov rcu_read_unlock(); 109780eae209SPetko Manolov (*pos)++; 109880eae209SPetko Manolov 109980eae209SPetko Manolov return (&entry->list == ima_rules) ? NULL : entry; 110080eae209SPetko Manolov } 110180eae209SPetko Manolov 110280eae209SPetko Manolov void ima_policy_stop(struct seq_file *m, void *v) 110380eae209SPetko Manolov { 110480eae209SPetko Manolov } 110580eae209SPetko Manolov 110680eae209SPetko Manolov #define pt(token) policy_tokens[token + Opt_err].pattern 110780eae209SPetko Manolov #define mt(token) mask_tokens[token] 110880eae209SPetko Manolov 1109b5269ab3SMimi Zohar /* 1110b5269ab3SMimi Zohar * policy_func_show - display the ima_hooks policy rule 1111b5269ab3SMimi Zohar */ 1112b5269ab3SMimi Zohar static void policy_func_show(struct seq_file *m, enum ima_hooks func) 1113b5269ab3SMimi Zohar { 11142663218bSThiago Jung Bauermann if (func > 0 && func < MAX_CHECK) 11152663218bSThiago Jung Bauermann seq_printf(m, "func=%s ", func_tokens[func]); 11162663218bSThiago Jung Bauermann else 11172663218bSThiago Jung Bauermann seq_printf(m, "func=%d ", func); 1118b5269ab3SMimi Zohar } 1119b5269ab3SMimi Zohar 112080eae209SPetko Manolov int ima_policy_show(struct seq_file *m, void *v) 112180eae209SPetko Manolov { 112280eae209SPetko Manolov struct ima_rule_entry *entry = v; 1123b8b57278SAndy Shevchenko int i; 112480eae209SPetko Manolov char tbuf[64] = {0,}; 112580eae209SPetko Manolov 112680eae209SPetko Manolov rcu_read_lock(); 112780eae209SPetko Manolov 112880eae209SPetko Manolov if (entry->action & MEASURE) 112980eae209SPetko Manolov seq_puts(m, pt(Opt_measure)); 113080eae209SPetko Manolov if (entry->action & DONT_MEASURE) 113180eae209SPetko Manolov seq_puts(m, pt(Opt_dont_measure)); 113280eae209SPetko Manolov if (entry->action & APPRAISE) 113380eae209SPetko Manolov seq_puts(m, pt(Opt_appraise)); 113480eae209SPetko Manolov if (entry->action & DONT_APPRAISE) 113580eae209SPetko Manolov seq_puts(m, pt(Opt_dont_appraise)); 113680eae209SPetko Manolov if (entry->action & AUDIT) 113780eae209SPetko Manolov seq_puts(m, pt(Opt_audit)); 1138da1b0029SMimi Zohar if (entry->action & HASH) 1139da1b0029SMimi Zohar seq_puts(m, pt(Opt_hash)); 1140da1b0029SMimi Zohar if (entry->action & DONT_HASH) 1141da1b0029SMimi Zohar seq_puts(m, pt(Opt_dont_hash)); 114280eae209SPetko Manolov 114380eae209SPetko Manolov seq_puts(m, " "); 114480eae209SPetko Manolov 1145b5269ab3SMimi Zohar if (entry->flags & IMA_FUNC) 1146b5269ab3SMimi Zohar policy_func_show(m, entry->func); 114780eae209SPetko Manolov 114880eae209SPetko Manolov if (entry->flags & IMA_MASK) { 114980eae209SPetko Manolov if (entry->mask & MAY_EXEC) 115080eae209SPetko Manolov seq_printf(m, pt(Opt_mask), mt(mask_exec)); 115180eae209SPetko Manolov if (entry->mask & MAY_WRITE) 115280eae209SPetko Manolov seq_printf(m, pt(Opt_mask), mt(mask_write)); 115380eae209SPetko Manolov if (entry->mask & MAY_READ) 115480eae209SPetko Manolov seq_printf(m, pt(Opt_mask), mt(mask_read)); 115580eae209SPetko Manolov if (entry->mask & MAY_APPEND) 115680eae209SPetko Manolov seq_printf(m, pt(Opt_mask), mt(mask_append)); 115780eae209SPetko Manolov seq_puts(m, " "); 115880eae209SPetko Manolov } 115980eae209SPetko Manolov 116080eae209SPetko Manolov if (entry->flags & IMA_FSMAGIC) { 116180eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "0x%lx", entry->fsmagic); 116280eae209SPetko Manolov seq_printf(m, pt(Opt_fsmagic), tbuf); 116380eae209SPetko Manolov seq_puts(m, " "); 116480eae209SPetko Manolov } 116580eae209SPetko Manolov 1166f1b08bbcSMimi Zohar if (entry->flags & IMA_FSNAME) { 1167f1b08bbcSMimi Zohar snprintf(tbuf, sizeof(tbuf), "%s", entry->fsname); 1168f1b08bbcSMimi Zohar seq_printf(m, pt(Opt_fsname), tbuf); 1169f1b08bbcSMimi Zohar seq_puts(m, " "); 1170f1b08bbcSMimi Zohar } 1171f1b08bbcSMimi Zohar 11720260643cSEric Richter if (entry->flags & IMA_PCR) { 11730260643cSEric Richter snprintf(tbuf, sizeof(tbuf), "%d", entry->pcr); 11740260643cSEric Richter seq_printf(m, pt(Opt_pcr), tbuf); 11750260643cSEric Richter seq_puts(m, " "); 11760260643cSEric Richter } 11770260643cSEric Richter 117880eae209SPetko Manolov if (entry->flags & IMA_FSUUID) { 1179787d8c53SChristoph Hellwig seq_printf(m, "fsuuid=%pU", &entry->fsuuid); 118080eae209SPetko Manolov seq_puts(m, " "); 118180eae209SPetko Manolov } 118280eae209SPetko Manolov 118380eae209SPetko Manolov if (entry->flags & IMA_UID) { 118480eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); 11853dd0c8d0SMikhail Kurinnoi if (entry->uid_op == &uid_gt) 11863dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_uid_gt), tbuf); 11873dd0c8d0SMikhail Kurinnoi else if (entry->uid_op == &uid_lt) 11883dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_uid_lt), tbuf); 11893dd0c8d0SMikhail Kurinnoi else 11903dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_uid_eq), tbuf); 119180eae209SPetko Manolov seq_puts(m, " "); 119280eae209SPetko Manolov } 119380eae209SPetko Manolov 119480eae209SPetko Manolov if (entry->flags & IMA_EUID) { 119580eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); 11963dd0c8d0SMikhail Kurinnoi if (entry->uid_op == &uid_gt) 11973dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_euid_gt), tbuf); 11983dd0c8d0SMikhail Kurinnoi else if (entry->uid_op == &uid_lt) 11993dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_euid_lt), tbuf); 12003dd0c8d0SMikhail Kurinnoi else 12013dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_euid_eq), tbuf); 120280eae209SPetko Manolov seq_puts(m, " "); 120380eae209SPetko Manolov } 120480eae209SPetko Manolov 120580eae209SPetko Manolov if (entry->flags & IMA_FOWNER) { 120680eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); 12073dd0c8d0SMikhail Kurinnoi if (entry->fowner_op == &uid_gt) 12083dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_fowner_gt), tbuf); 12093dd0c8d0SMikhail Kurinnoi else if (entry->fowner_op == &uid_lt) 12103dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_fowner_lt), tbuf); 12113dd0c8d0SMikhail Kurinnoi else 12123dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_fowner_eq), tbuf); 121380eae209SPetko Manolov seq_puts(m, " "); 121480eae209SPetko Manolov } 121580eae209SPetko Manolov 121680eae209SPetko Manolov for (i = 0; i < MAX_LSM_RULES; i++) { 121780eae209SPetko Manolov if (entry->lsm[i].rule) { 121880eae209SPetko Manolov switch (i) { 121980eae209SPetko Manolov case LSM_OBJ_USER: 122080eae209SPetko Manolov seq_printf(m, pt(Opt_obj_user), 122180eae209SPetko Manolov (char *)entry->lsm[i].args_p); 122280eae209SPetko Manolov break; 122380eae209SPetko Manolov case LSM_OBJ_ROLE: 122480eae209SPetko Manolov seq_printf(m, pt(Opt_obj_role), 122580eae209SPetko Manolov (char *)entry->lsm[i].args_p); 122680eae209SPetko Manolov break; 122780eae209SPetko Manolov case LSM_OBJ_TYPE: 122880eae209SPetko Manolov seq_printf(m, pt(Opt_obj_type), 122980eae209SPetko Manolov (char *)entry->lsm[i].args_p); 123080eae209SPetko Manolov break; 123180eae209SPetko Manolov case LSM_SUBJ_USER: 123280eae209SPetko Manolov seq_printf(m, pt(Opt_subj_user), 123380eae209SPetko Manolov (char *)entry->lsm[i].args_p); 123480eae209SPetko Manolov break; 123580eae209SPetko Manolov case LSM_SUBJ_ROLE: 123680eae209SPetko Manolov seq_printf(m, pt(Opt_subj_role), 123780eae209SPetko Manolov (char *)entry->lsm[i].args_p); 123880eae209SPetko Manolov break; 123980eae209SPetko Manolov case LSM_SUBJ_TYPE: 124080eae209SPetko Manolov seq_printf(m, pt(Opt_subj_type), 124180eae209SPetko Manolov (char *)entry->lsm[i].args_p); 124280eae209SPetko Manolov break; 124380eae209SPetko Manolov } 124480eae209SPetko Manolov } 124580eae209SPetko Manolov } 124680eae209SPetko Manolov if (entry->flags & IMA_DIGSIG_REQUIRED) 124780eae209SPetko Manolov seq_puts(m, "appraise_type=imasig "); 124880eae209SPetko Manolov if (entry->flags & IMA_PERMIT_DIRECTIO) 124980eae209SPetko Manolov seq_puts(m, "permit_directio "); 125080eae209SPetko Manolov rcu_read_unlock(); 125180eae209SPetko Manolov seq_puts(m, "\n"); 125280eae209SPetko Manolov return 0; 125380eae209SPetko Manolov } 125480eae209SPetko Manolov #endif /* CONFIG_IMA_READ_POLICY */ 1255