1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 23323eec9SMimi Zohar /* 33323eec9SMimi Zohar * Copyright (C) 2008 IBM Corporation 43323eec9SMimi Zohar * Author: Mimi Zohar <zohar@us.ibm.com> 53323eec9SMimi Zohar * 63323eec9SMimi Zohar * ima_policy.c 73323eec9SMimi Zohar * - initialize default measure policy rules 83323eec9SMimi Zohar */ 93878d505SThiago Jung Bauermann 10876979c9SPaul Gortmaker #include <linux/init.h> 113323eec9SMimi Zohar #include <linux/list.h> 12b89999d0SScott Branden #include <linux/kernel_read_file.h> 13cf222217SMimi Zohar #include <linux/fs.h> 143323eec9SMimi Zohar #include <linux/security.h> 153323eec9SMimi Zohar #include <linux/magic.h> 164af4662fSMimi Zohar #include <linux/parser.h> 175a0e3ad6STejun Heo #include <linux/slab.h> 1838d859f9SPetko Manolov #include <linux/rculist.h> 1980eae209SPetko Manolov #include <linux/seq_file.h> 2061917062SNayna Jain #include <linux/ima.h> 213323eec9SMimi Zohar 223323eec9SMimi Zohar #include "ima.h" 233323eec9SMimi Zohar 243323eec9SMimi Zohar /* flags definitions */ 253323eec9SMimi Zohar #define IMA_FUNC 0x0001 263323eec9SMimi Zohar #define IMA_MASK 0x0002 273323eec9SMimi Zohar #define IMA_FSMAGIC 0x0004 283323eec9SMimi Zohar #define IMA_UID 0x0008 2907f6a794SMimi Zohar #define IMA_FOWNER 0x0010 3085865c1fSDmitry Kasatkin #define IMA_FSUUID 0x0020 314351c294SMimi Zohar #define IMA_INMASK 0x0040 32139069efSMimi Zohar #define IMA_EUID 0x0080 330260643cSEric Richter #define IMA_PCR 0x0100 34f1b08bbcSMimi Zohar #define IMA_FSNAME 0x0200 352b60c0ecSLakshmi Ramasubramanian #define IMA_KEYRINGS 0x0400 3647d76a48STushar Sugandhi #define IMA_LABEL 0x0800 371624dc00STHOBY Simon #define IMA_VALIDATE_ALGOS 0x1000 3840224c41SCurtis Veit #define IMA_GID 0x2000 3940224c41SCurtis Veit #define IMA_EGID 0x4000 4040224c41SCurtis Veit #define IMA_FGROUP 0x8000 413323eec9SMimi Zohar 422fe5d6deSMimi Zohar #define UNKNOWN 0 4345e2472eSDmitry Kasatkin #define MEASURE 0x0001 /* same as IMA_MEASURE */ 4445e2472eSDmitry Kasatkin #define DONT_MEASURE 0x0002 4545e2472eSDmitry Kasatkin #define APPRAISE 0x0004 /* same as IMA_APPRAISE */ 4645e2472eSDmitry Kasatkin #define DONT_APPRAISE 0x0008 47e7c568e0SPeter Moody #define AUDIT 0x0040 48da1b0029SMimi Zohar #define HASH 0x0100 49da1b0029SMimi Zohar #define DONT_HASH 0x0200 504af4662fSMimi Zohar 510260643cSEric Richter #define INVALID_PCR(a) (((a) < 0) || \ 52c593642cSPankaj Bharadiya (a) >= (sizeof_field(struct integrity_iint_cache, measured_pcrs) * 8)) 530260643cSEric Richter 54a756024eSRoberto Sassu int ima_policy_flag; 556ad6afa1SMimi Zohar static int temp_ima_appraise; 56ef96837bSMimi Zohar static int build_ima_appraise __ro_after_init; 57a756024eSRoberto Sassu 584f2946aaSTHOBY Simon atomic_t ima_setxattr_allowed_hash_algorithms; 594f2946aaSTHOBY Simon 604af4662fSMimi Zohar #define MAX_LSM_RULES 6 614af4662fSMimi Zohar enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, 624af4662fSMimi Zohar LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE 634af4662fSMimi Zohar }; 643323eec9SMimi Zohar 6524fd03c8SMimi Zohar enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; 6624fd03c8SMimi Zohar 67c52657d9SNayna Jain enum policy_rule_list { IMA_DEFAULT_POLICY = 1, IMA_CUSTOM_POLICY }; 68c52657d9SNayna Jain 69176377d9STyler Hicks struct ima_rule_opt_list { 70176377d9STyler Hicks size_t count; 71176377d9STyler Hicks char *items[]; 72176377d9STyler Hicks }; 73176377d9STyler Hicks 7407f6a794SMimi Zohar struct ima_rule_entry { 753323eec9SMimi Zohar struct list_head list; 762fe5d6deSMimi Zohar int action; 773323eec9SMimi Zohar unsigned int flags; 783323eec9SMimi Zohar enum ima_hooks func; 793323eec9SMimi Zohar int mask; 803323eec9SMimi Zohar unsigned long fsmagic; 81787d8c53SChristoph Hellwig uuid_t fsuuid; 828b94eea4SEric W. Biederman kuid_t uid; 8340224c41SCurtis Veit kgid_t gid; 8488265322SLinus Torvalds kuid_t fowner; 8540224c41SCurtis Veit kgid_t fgroup; 8630d8764aSAlex Henrie bool (*uid_op)(kuid_t cred_uid, kuid_t rule_uid); /* Handlers for operators */ 8740224c41SCurtis Veit bool (*gid_op)(kgid_t cred_gid, kgid_t rule_gid); 8830d8764aSAlex Henrie bool (*fowner_op)(kuid_t cred_uid, kuid_t rule_uid); /* uid_eq(), uid_gt(), uid_lt() */ 8940224c41SCurtis Veit bool (*fgroup_op)(kgid_t cred_gid, kgid_t rule_gid); /* gid_eq(), gid_gt(), gid_lt() */ 900260643cSEric Richter int pcr; 911624dc00STHOBY Simon unsigned int allowed_algos; /* bitfield of allowed hash algorithms */ 924af4662fSMimi Zohar struct { 934af4662fSMimi Zohar void *rule; /* LSM file metadata specific */ 94aa0c0227STyler Hicks char *args_p; /* audit value */ 954af4662fSMimi Zohar int type; /* audit type */ 964af4662fSMimi Zohar } lsm[MAX_LSM_RULES]; 97f1b08bbcSMimi Zohar char *fsname; 98176377d9STyler Hicks struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */ 9947d76a48STushar Sugandhi struct ima_rule_opt_list *label; /* Measure data grouped under this label */ 10019453ce0SMatthew Garrett struct ima_template_desc *template; 1013323eec9SMimi Zohar }; 1023323eec9SMimi Zohar 1035789ba3bSEric Paris /* 1041624dc00STHOBY Simon * sanity check in case the kernels gains more hash algorithms that can 1051624dc00STHOBY Simon * fit in an unsigned int 1061624dc00STHOBY Simon */ 1071624dc00STHOBY Simon static_assert( 1081624dc00STHOBY Simon 8 * sizeof(unsigned int) >= HASH_ALGO__LAST, 1091624dc00STHOBY Simon "The bitfield allowed_algos in ima_rule_entry is too small to contain all the supported hash algorithms, consider using a bigger type"); 1101624dc00STHOBY Simon 1111624dc00STHOBY Simon /* 1125789ba3bSEric Paris * Without LSM specific knowledge, the default policy can only be 11340224c41SCurtis Veit * written in terms of .action, .func, .mask, .fsmagic, .uid, .gid, 11440224c41SCurtis Veit * .fowner, and .fgroup 1154af4662fSMimi Zohar */ 1165789ba3bSEric Paris 1175789ba3bSEric Paris /* 1185789ba3bSEric Paris * The minimum rule set to allow for full TCB coverage. Measures all files 1195789ba3bSEric Paris * opened or mmap for exec and everything read by root. Dangerous because 1205789ba3bSEric Paris * normal users can easily run the machine out of memory simply building 1215789ba3bSEric Paris * and running executables. 1225789ba3bSEric Paris */ 123bad4417bSJames Morris static struct ima_rule_entry dont_measure_rules[] __ro_after_init = { 12475834fc3SEric Paris {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 1253323eec9SMimi Zohar {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, 1263323eec9SMimi Zohar {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, 1273323eec9SMimi Zohar {.action = DONT_MEASURE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, 1288445d64dSDmitry Kasatkin {.action = DONT_MEASURE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 1298445d64dSDmitry Kasatkin {.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, 13075834fc3SEric Paris {.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, 13175834fc3SEric Paris {.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, 1321c070b18SMartin Townsend {.action = DONT_MEASURE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, 1336438de9fSRoberto Sassu {.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC, 1346438de9fSRoberto Sassu .flags = IMA_FSMAGIC}, 13582e3bb4dSLaura Abbott {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC, 13682e3bb4dSLaura Abbott .flags = IMA_FSMAGIC}, 137060190fbSMimi Zohar {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, 138060190fbSMimi Zohar {.action = DONT_MEASURE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC} 13924fd03c8SMimi Zohar }; 14024fd03c8SMimi Zohar 141bad4417bSJames Morris static struct ima_rule_entry original_measurement_rules[] __ro_after_init = { 14216cac49fSMimi Zohar {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, 1433323eec9SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 1443323eec9SMimi Zohar {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, 1453323eec9SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 14624fd03c8SMimi Zohar {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 1473dd0c8d0SMikhail Kurinnoi .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, 1483dd0c8d0SMikhail Kurinnoi .flags = IMA_FUNC | IMA_MASK | IMA_UID}, 14924fd03c8SMimi Zohar {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, 15024fd03c8SMimi Zohar {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, 15124fd03c8SMimi Zohar }; 15224fd03c8SMimi Zohar 153bad4417bSJames Morris static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { 15424fd03c8SMimi Zohar {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, 15524fd03c8SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 15624fd03c8SMimi Zohar {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, 15724fd03c8SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 15824fd03c8SMimi Zohar {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 1593dd0c8d0SMikhail Kurinnoi .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, 1603dd0c8d0SMikhail Kurinnoi .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, 16124fd03c8SMimi Zohar {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 1623dd0c8d0SMikhail Kurinnoi .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, 1633dd0c8d0SMikhail Kurinnoi .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, 164fdf90729SMimi Zohar {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, 1655a9196d7SMimi Zohar {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, 16619f8a847SMimi Zohar {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, 1673323eec9SMimi Zohar }; 1683323eec9SMimi Zohar 169bad4417bSJames Morris static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { 17007f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 17107f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, 17207f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, 17307f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, 17407f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = RAMFS_MAGIC, .flags = IMA_FSMAGIC}, 17507f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 17607f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, 17707f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, 17807f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, 1791c070b18SMartin Townsend {.action = DONT_APPRAISE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, 180cd025f7fSMimi Zohar {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, 181060190fbSMimi Zohar {.action = DONT_APPRAISE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC}, 18207f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 18382e3bb4dSLaura Abbott {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 18495ee08faSMimi Zohar #ifdef CONFIG_IMA_WRITE_POLICY 18595ee08faSMimi Zohar {.action = APPRAISE, .func = POLICY_CHECK, 18695ee08faSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 18795ee08faSMimi Zohar #endif 188c57782c1SDmitry Kasatkin #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT 1893dd0c8d0SMikhail Kurinnoi {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, 1903dd0c8d0SMikhail Kurinnoi .flags = IMA_FOWNER}, 191c57782c1SDmitry Kasatkin #else 192c57782c1SDmitry Kasatkin /* force signature */ 1933dd0c8d0SMikhail Kurinnoi {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, 194c57782c1SDmitry Kasatkin .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, 195c57782c1SDmitry Kasatkin #endif 19607f6a794SMimi Zohar }; 1973323eec9SMimi Zohar 198ef96837bSMimi Zohar static struct ima_rule_entry build_appraise_rules[] __ro_after_init = { 199ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_MODULE_SIGS 200ef96837bSMimi Zohar {.action = APPRAISE, .func = MODULE_CHECK, 201ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 202ef96837bSMimi Zohar #endif 203ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_FIRMWARE_SIGS 204ef96837bSMimi Zohar {.action = APPRAISE, .func = FIRMWARE_CHECK, 205ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 206ef96837bSMimi Zohar #endif 207ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_KEXEC_SIGS 208ef96837bSMimi Zohar {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK, 209ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 210ef96837bSMimi Zohar #endif 211ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_POLICY_SIGS 212ef96837bSMimi Zohar {.action = APPRAISE, .func = POLICY_CHECK, 213ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 214ef96837bSMimi Zohar #endif 215ef96837bSMimi Zohar }; 216ef96837bSMimi Zohar 217503ceaefSMimi Zohar static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { 218503ceaefSMimi Zohar {.action = APPRAISE, .func = MODULE_CHECK, 219503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 220503ceaefSMimi Zohar {.action = APPRAISE, .func = FIRMWARE_CHECK, 221503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 222503ceaefSMimi Zohar {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK, 223503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 224503ceaefSMimi Zohar {.action = APPRAISE, .func = POLICY_CHECK, 225503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 226503ceaefSMimi Zohar }; 227503ceaefSMimi Zohar 22803cee168SLakshmi Ramasubramanian static struct ima_rule_entry critical_data_rules[] __ro_after_init = { 22903cee168SLakshmi Ramasubramanian {.action = MEASURE, .func = CRITICAL_DATA, .flags = IMA_FUNC}, 23003cee168SLakshmi Ramasubramanian }; 23103cee168SLakshmi Ramasubramanian 23261917062SNayna Jain /* An array of architecture specific rules */ 23368f25290SYueHaibing static struct ima_rule_entry *arch_policy_entry __ro_after_init; 23461917062SNayna Jain 23507f6a794SMimi Zohar static LIST_HEAD(ima_default_rules); 23607f6a794SMimi Zohar static LIST_HEAD(ima_policy_rules); 23738d859f9SPetko Manolov static LIST_HEAD(ima_temp_rules); 238eb0782bbSliqiong static struct list_head __rcu *ima_rules = (struct list_head __rcu *)(&ima_default_rules); 23907f6a794SMimi Zohar 24024fd03c8SMimi Zohar static int ima_policy __initdata; 24138d859f9SPetko Manolov 24207f6a794SMimi Zohar static int __init default_measure_policy_setup(char *str) 2435789ba3bSEric Paris { 24424fd03c8SMimi Zohar if (ima_policy) 24524fd03c8SMimi Zohar return 1; 24624fd03c8SMimi Zohar 24724fd03c8SMimi Zohar ima_policy = ORIGINAL_TCB; 2485789ba3bSEric Paris return 1; 2495789ba3bSEric Paris } 25007f6a794SMimi Zohar __setup("ima_tcb", default_measure_policy_setup); 25107f6a794SMimi Zohar 25233ce9549SMimi Zohar static bool ima_use_appraise_tcb __initdata; 253503ceaefSMimi Zohar static bool ima_use_secure_boot __initdata; 25403cee168SLakshmi Ramasubramanian static bool ima_use_critical_data __initdata; 2559e67028eSMimi Zohar static bool ima_fail_unverifiable_sigs __ro_after_init; 25624fd03c8SMimi Zohar static int __init policy_setup(char *str) 25724fd03c8SMimi Zohar { 25833ce9549SMimi Zohar char *p; 25924fd03c8SMimi Zohar 26033ce9549SMimi Zohar while ((p = strsep(&str, " |\n")) != NULL) { 26133ce9549SMimi Zohar if (*p == ' ') 26233ce9549SMimi Zohar continue; 26333ce9549SMimi Zohar if ((strcmp(p, "tcb") == 0) && !ima_policy) 26424fd03c8SMimi Zohar ima_policy = DEFAULT_TCB; 26533ce9549SMimi Zohar else if (strcmp(p, "appraise_tcb") == 0) 26639adb925SThomas Meyer ima_use_appraise_tcb = true; 267503ceaefSMimi Zohar else if (strcmp(p, "secure_boot") == 0) 26839adb925SThomas Meyer ima_use_secure_boot = true; 26903cee168SLakshmi Ramasubramanian else if (strcmp(p, "critical_data") == 0) 27003cee168SLakshmi Ramasubramanian ima_use_critical_data = true; 2719e67028eSMimi Zohar else if (strcmp(p, "fail_securely") == 0) 2729e67028eSMimi Zohar ima_fail_unverifiable_sigs = true; 2737fe2bb7eSBruno Meneguele else 2747fe2bb7eSBruno Meneguele pr_err("policy \"%s\" not found", p); 27533ce9549SMimi Zohar } 27624fd03c8SMimi Zohar 27724fd03c8SMimi Zohar return 1; 27824fd03c8SMimi Zohar } 27924fd03c8SMimi Zohar __setup("ima_policy=", policy_setup); 28024fd03c8SMimi Zohar 28107f6a794SMimi Zohar static int __init default_appraise_policy_setup(char *str) 28207f6a794SMimi Zohar { 28339adb925SThomas Meyer ima_use_appraise_tcb = true; 28407f6a794SMimi Zohar return 1; 28507f6a794SMimi Zohar } 28607f6a794SMimi Zohar __setup("ima_appraise_tcb", default_appraise_policy_setup); 2875789ba3bSEric Paris 288176377d9STyler Hicks static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src) 289176377d9STyler Hicks { 290176377d9STyler Hicks struct ima_rule_opt_list *opt_list; 291176377d9STyler Hicks size_t count = 0; 292176377d9STyler Hicks char *src_copy; 293176377d9STyler Hicks char *cur, *next; 294176377d9STyler Hicks size_t i; 295176377d9STyler Hicks 296176377d9STyler Hicks src_copy = match_strdup(src); 297176377d9STyler Hicks if (!src_copy) 298176377d9STyler Hicks return ERR_PTR(-ENOMEM); 299176377d9STyler Hicks 300176377d9STyler Hicks next = src_copy; 301176377d9STyler Hicks while ((cur = strsep(&next, "|"))) { 302176377d9STyler Hicks /* Don't accept an empty list item */ 303176377d9STyler Hicks if (!(*cur)) { 304176377d9STyler Hicks kfree(src_copy); 305176377d9STyler Hicks return ERR_PTR(-EINVAL); 306176377d9STyler Hicks } 307176377d9STyler Hicks count++; 308176377d9STyler Hicks } 309176377d9STyler Hicks 310176377d9STyler Hicks /* Don't accept an empty list */ 311176377d9STyler Hicks if (!count) { 312176377d9STyler Hicks kfree(src_copy); 313176377d9STyler Hicks return ERR_PTR(-EINVAL); 314176377d9STyler Hicks } 315176377d9STyler Hicks 316176377d9STyler Hicks opt_list = kzalloc(struct_size(opt_list, items, count), GFP_KERNEL); 317176377d9STyler Hicks if (!opt_list) { 318176377d9STyler Hicks kfree(src_copy); 319176377d9STyler Hicks return ERR_PTR(-ENOMEM); 320176377d9STyler Hicks } 321176377d9STyler Hicks 322176377d9STyler Hicks /* 323176377d9STyler Hicks * strsep() has already replaced all instances of '|' with '\0', 324176377d9STyler Hicks * leaving a byte sequence of NUL-terminated strings. Reference each 325176377d9STyler Hicks * string with the array of items. 326176377d9STyler Hicks * 327176377d9STyler Hicks * IMPORTANT: Ownership of the allocated buffer is transferred from 328176377d9STyler Hicks * src_copy to the first element in the items array. To free the 329176377d9STyler Hicks * buffer, kfree() must only be called on the first element of the 330176377d9STyler Hicks * array. 331176377d9STyler Hicks */ 332176377d9STyler Hicks for (i = 0, cur = src_copy; i < count; i++) { 333176377d9STyler Hicks opt_list->items[i] = cur; 334176377d9STyler Hicks cur = strchr(cur, '\0') + 1; 335176377d9STyler Hicks } 336176377d9STyler Hicks opt_list->count = count; 337176377d9STyler Hicks 338176377d9STyler Hicks return opt_list; 339176377d9STyler Hicks } 340176377d9STyler Hicks 341176377d9STyler Hicks static void ima_free_rule_opt_list(struct ima_rule_opt_list *opt_list) 342176377d9STyler Hicks { 343176377d9STyler Hicks if (!opt_list) 344176377d9STyler Hicks return; 345176377d9STyler Hicks 346176377d9STyler Hicks if (opt_list->count) { 347176377d9STyler Hicks kfree(opt_list->items[0]); 348176377d9STyler Hicks opt_list->count = 0; 349176377d9STyler Hicks } 350176377d9STyler Hicks 351176377d9STyler Hicks kfree(opt_list); 352176377d9STyler Hicks } 353176377d9STyler Hicks 354b1694245SJanne Karhunen static void ima_lsm_free_rule(struct ima_rule_entry *entry) 3557163a993SMimi Zohar { 3567163a993SMimi Zohar int i; 3577163a993SMimi Zohar 358b1694245SJanne Karhunen for (i = 0; i < MAX_LSM_RULES; i++) { 359b8867eedSTyler Hicks ima_filter_rule_free(entry->lsm[i].rule); 360b1694245SJanne Karhunen kfree(entry->lsm[i].args_p); 361b1694245SJanne Karhunen } 362465aee77STyler Hicks } 363465aee77STyler Hicks 364465aee77STyler Hicks static void ima_free_rule(struct ima_rule_entry *entry) 365465aee77STyler Hicks { 366465aee77STyler Hicks if (!entry) 367465aee77STyler Hicks return; 368465aee77STyler Hicks 369465aee77STyler Hicks /* 370465aee77STyler Hicks * entry->template->fields may be allocated in ima_parse_rule() but that 371465aee77STyler Hicks * reference is owned by the corresponding ima_template_desc element in 372465aee77STyler Hicks * the defined_templates list and cannot be freed here 373465aee77STyler Hicks */ 374465aee77STyler Hicks kfree(entry->fsname); 375176377d9STyler Hicks ima_free_rule_opt_list(entry->keyrings); 376465aee77STyler Hicks ima_lsm_free_rule(entry); 377b1694245SJanne Karhunen kfree(entry); 378b1694245SJanne Karhunen } 379b1694245SJanne Karhunen 380b1694245SJanne Karhunen static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry) 381b1694245SJanne Karhunen { 382b1694245SJanne Karhunen struct ima_rule_entry *nentry; 383483ec26eSJanne Karhunen int i; 384b1694245SJanne Karhunen 385b1694245SJanne Karhunen /* 386b1694245SJanne Karhunen * Immutable elements are copied over as pointers and data; only 387b1694245SJanne Karhunen * lsm rules can change 388b1694245SJanne Karhunen */ 389f60c826dSAlex Dewar nentry = kmemdup(entry, sizeof(*nentry), GFP_KERNEL); 390f60c826dSAlex Dewar if (!nentry) 391f60c826dSAlex Dewar return NULL; 392f60c826dSAlex Dewar 393c593642cSPankaj Bharadiya memset(nentry->lsm, 0, sizeof_field(struct ima_rule_entry, lsm)); 394b1694245SJanne Karhunen 3957163a993SMimi Zohar for (i = 0; i < MAX_LSM_RULES; i++) { 396483ec26eSJanne Karhunen if (!entry->lsm[i].args_p) 3977163a993SMimi Zohar continue; 398b1694245SJanne Karhunen 399b1694245SJanne Karhunen nentry->lsm[i].type = entry->lsm[i].type; 40039e5993dSTyler Hicks nentry->lsm[i].args_p = entry->lsm[i].args_p; 401b1694245SJanne Karhunen 402b8867eedSTyler Hicks ima_filter_rule_init(nentry->lsm[i].type, Audit_equal, 403b1694245SJanne Karhunen nentry->lsm[i].args_p, 404b1694245SJanne Karhunen &nentry->lsm[i].rule); 405483ec26eSJanne Karhunen if (!nentry->lsm[i].rule) 406483ec26eSJanne Karhunen pr_warn("rule for LSM \'%s\' is undefined\n", 407aa0c0227STyler Hicks nentry->lsm[i].args_p); 408b1694245SJanne Karhunen } 409b1694245SJanne Karhunen return nentry; 410b1694245SJanne Karhunen } 411b1694245SJanne Karhunen 412b1694245SJanne Karhunen static int ima_lsm_update_rule(struct ima_rule_entry *entry) 413b1694245SJanne Karhunen { 414*d57378d3SGUO Zihua int i; 415b1694245SJanne Karhunen struct ima_rule_entry *nentry; 416b1694245SJanne Karhunen 417b1694245SJanne Karhunen nentry = ima_lsm_copy_rule(entry); 418b1694245SJanne Karhunen if (!nentry) 419b1694245SJanne Karhunen return -ENOMEM; 420b1694245SJanne Karhunen 421b1694245SJanne Karhunen list_replace_rcu(&entry->list, &nentry->list); 422b1694245SJanne Karhunen synchronize_rcu(); 423465aee77STyler Hicks /* 424465aee77STyler Hicks * ima_lsm_copy_rule() shallow copied all references, except for the 425465aee77STyler Hicks * LSM references, from entry to nentry so we only want to free the LSM 42665603435SAustin Kim * references and the entry itself. All other memory references will now 427465aee77STyler Hicks * be owned by nentry. 428465aee77STyler Hicks */ 429*d57378d3SGUO Zihua for (i = 0; i < MAX_LSM_RULES; i++) 430*d57378d3SGUO Zihua ima_filter_rule_free(entry->lsm[i].rule); 431465aee77STyler Hicks kfree(entry); 432b1694245SJanne Karhunen 433b1694245SJanne Karhunen return 0; 434b1694245SJanne Karhunen } 435b1694245SJanne Karhunen 436db2045f5STyler Hicks static bool ima_rule_contains_lsm_cond(struct ima_rule_entry *entry) 437db2045f5STyler Hicks { 438db2045f5STyler Hicks int i; 439db2045f5STyler Hicks 440db2045f5STyler Hicks for (i = 0; i < MAX_LSM_RULES; i++) 441db2045f5STyler Hicks if (entry->lsm[i].args_p) 442db2045f5STyler Hicks return true; 443db2045f5STyler Hicks 444db2045f5STyler Hicks return false; 445db2045f5STyler Hicks } 446db2045f5STyler Hicks 447b1694245SJanne Karhunen /* 448b1694245SJanne Karhunen * The LSM policy can be reloaded, leaving the IMA LSM based rules referring 449b1694245SJanne Karhunen * to the old, stale LSM policy. Update the IMA LSM based rules to reflect 450b1694245SJanne Karhunen * the reloaded LSM policy. 451b1694245SJanne Karhunen */ 452b1694245SJanne Karhunen static void ima_lsm_update_rules(void) 453b1694245SJanne Karhunen { 454b1694245SJanne Karhunen struct ima_rule_entry *entry, *e; 455592b24cbSTyler Hicks int result; 456b1694245SJanne Karhunen 457b1694245SJanne Karhunen list_for_each_entry_safe(entry, e, &ima_policy_rules, list) { 458592b24cbSTyler Hicks if (!ima_rule_contains_lsm_cond(entry)) 459b1694245SJanne Karhunen continue; 460b1694245SJanne Karhunen 461b1694245SJanne Karhunen result = ima_lsm_update_rule(entry); 462b1694245SJanne Karhunen if (result) { 463483ec26eSJanne Karhunen pr_err("lsm rule update error %d\n", result); 464b1694245SJanne Karhunen return; 465b1694245SJanne Karhunen } 466b1694245SJanne Karhunen } 467b1694245SJanne Karhunen } 468b1694245SJanne Karhunen 469b1694245SJanne Karhunen int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, 470b1694245SJanne Karhunen void *lsm_data) 471b1694245SJanne Karhunen { 472b1694245SJanne Karhunen if (event != LSM_POLICY_CHANGE) 473b1694245SJanne Karhunen return NOTIFY_DONE; 474b1694245SJanne Karhunen 475b1694245SJanne Karhunen ima_lsm_update_rules(); 476b1694245SJanne Karhunen return NOTIFY_OK; 4777163a993SMimi Zohar } 4787163a993SMimi Zohar 4793323eec9SMimi Zohar /** 4802b4a2474STushar Sugandhi * ima_match_rule_data - determine whether func_data matches the policy rule 481e9085e0aSLakshmi Ramasubramanian * @rule: a pointer to a rule 4822b4a2474STushar Sugandhi * @func_data: data to match against the measure rule data 483e9085e0aSLakshmi Ramasubramanian * @cred: a pointer to a credentials structure for user validation 484e9085e0aSLakshmi Ramasubramanian * 4852b4a2474STushar Sugandhi * Returns true if func_data matches one in the rule, false otherwise. 486e9085e0aSLakshmi Ramasubramanian */ 4872b4a2474STushar Sugandhi static bool ima_match_rule_data(struct ima_rule_entry *rule, 4882b4a2474STushar Sugandhi const char *func_data, 4892b4a2474STushar Sugandhi const struct cred *cred) 490e9085e0aSLakshmi Ramasubramanian { 4912b4a2474STushar Sugandhi const struct ima_rule_opt_list *opt_list = NULL; 492e9085e0aSLakshmi Ramasubramanian bool matched = false; 493176377d9STyler Hicks size_t i; 494e9085e0aSLakshmi Ramasubramanian 495e9085e0aSLakshmi Ramasubramanian if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid)) 496e9085e0aSLakshmi Ramasubramanian return false; 497e9085e0aSLakshmi Ramasubramanian 4982b4a2474STushar Sugandhi switch (rule->func) { 4992b4a2474STushar Sugandhi case KEY_CHECK: 500e9085e0aSLakshmi Ramasubramanian if (!rule->keyrings) 501e9085e0aSLakshmi Ramasubramanian return true; 502e9085e0aSLakshmi Ramasubramanian 5032b4a2474STushar Sugandhi opt_list = rule->keyrings; 5042b4a2474STushar Sugandhi break; 505c4e43aa2STushar Sugandhi case CRITICAL_DATA: 50647d76a48STushar Sugandhi if (!rule->label) 507c4e43aa2STushar Sugandhi return true; 50847d76a48STushar Sugandhi 50947d76a48STushar Sugandhi opt_list = rule->label; 51047d76a48STushar Sugandhi break; 5112b4a2474STushar Sugandhi default: 5122b4a2474STushar Sugandhi return false; 5132b4a2474STushar Sugandhi } 5142b4a2474STushar Sugandhi 5152b4a2474STushar Sugandhi if (!func_data) 516e9085e0aSLakshmi Ramasubramanian return false; 517e9085e0aSLakshmi Ramasubramanian 5182b4a2474STushar Sugandhi for (i = 0; i < opt_list->count; i++) { 5192b4a2474STushar Sugandhi if (!strcmp(opt_list->items[i], func_data)) { 520e9085e0aSLakshmi Ramasubramanian matched = true; 521e9085e0aSLakshmi Ramasubramanian break; 522e9085e0aSLakshmi Ramasubramanian } 523e9085e0aSLakshmi Ramasubramanian } 524e9085e0aSLakshmi Ramasubramanian 525e9085e0aSLakshmi Ramasubramanian return matched; 526e9085e0aSLakshmi Ramasubramanian } 527e9085e0aSLakshmi Ramasubramanian 528e9085e0aSLakshmi Ramasubramanian /** 529483ec26eSJanne Karhunen * ima_match_rules - determine whether an inode matches the policy rule. 5303323eec9SMimi Zohar * @rule: a pointer to a rule 531a2d2329eSChristian Brauner * @mnt_userns: user namespace of the mount the inode was found from 5323323eec9SMimi Zohar * @inode: a pointer to an inode 533d906c10dSMatthew Garrett * @cred: a pointer to a credentials structure for user validation 534d906c10dSMatthew Garrett * @secid: the secid of the task to be validated 5353323eec9SMimi Zohar * @func: LIM hook identifier 5363323eec9SMimi Zohar * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) 5372b4a2474STushar Sugandhi * @func_data: func specific data, may be NULL 5383323eec9SMimi Zohar * 5393323eec9SMimi Zohar * Returns true on rule match, false on failure. 5403323eec9SMimi Zohar */ 541a2d2329eSChristian Brauner static bool ima_match_rules(struct ima_rule_entry *rule, 542a2d2329eSChristian Brauner struct user_namespace *mnt_userns, 543a2d2329eSChristian Brauner struct inode *inode, const struct cred *cred, 544a2d2329eSChristian Brauner u32 secid, enum ima_hooks func, int mask, 5452b4a2474STushar Sugandhi const char *func_data) 5463323eec9SMimi Zohar { 5474af4662fSMimi Zohar int i; 5483323eec9SMimi Zohar 54909b1148eSDmitry Kasatkin if ((rule->flags & IMA_FUNC) && 55009b1148eSDmitry Kasatkin (rule->func != func && func != POST_SETATTR)) 5513323eec9SMimi Zohar return false; 552c4e43aa2STushar Sugandhi 553c4e43aa2STushar Sugandhi switch (func) { 554c4e43aa2STushar Sugandhi case KEY_CHECK: 555c4e43aa2STushar Sugandhi case CRITICAL_DATA: 556c4e43aa2STushar Sugandhi return ((rule->func == func) && 557c4e43aa2STushar Sugandhi ima_match_rule_data(rule, func_data, cred)); 558c4e43aa2STushar Sugandhi default: 559c4e43aa2STushar Sugandhi break; 560c4e43aa2STushar Sugandhi } 561c4e43aa2STushar Sugandhi 56209b1148eSDmitry Kasatkin if ((rule->flags & IMA_MASK) && 56309b1148eSDmitry Kasatkin (rule->mask != mask && func != POST_SETATTR)) 5643323eec9SMimi Zohar return false; 5654351c294SMimi Zohar if ((rule->flags & IMA_INMASK) && 5664351c294SMimi Zohar (!(rule->mask & mask) && func != POST_SETATTR)) 5674351c294SMimi Zohar return false; 5683323eec9SMimi Zohar if ((rule->flags & IMA_FSMAGIC) 5693323eec9SMimi Zohar && rule->fsmagic != inode->i_sb->s_magic) 5703323eec9SMimi Zohar return false; 571f1b08bbcSMimi Zohar if ((rule->flags & IMA_FSNAME) 572f1b08bbcSMimi Zohar && strcmp(rule->fsname, inode->i_sb->s_type->name)) 573f1b08bbcSMimi Zohar return false; 57485865c1fSDmitry Kasatkin if ((rule->flags & IMA_FSUUID) && 57585787090SChristoph Hellwig !uuid_equal(&rule->fsuuid, &inode->i_sb->s_uuid)) 57685865c1fSDmitry Kasatkin return false; 5773dd0c8d0SMikhail Kurinnoi if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid)) 5783323eec9SMimi Zohar return false; 579139069efSMimi Zohar if (rule->flags & IMA_EUID) { 580139069efSMimi Zohar if (has_capability_noaudit(current, CAP_SETUID)) { 5813dd0c8d0SMikhail Kurinnoi if (!rule->uid_op(cred->euid, rule->uid) 5823dd0c8d0SMikhail Kurinnoi && !rule->uid_op(cred->suid, rule->uid) 5833dd0c8d0SMikhail Kurinnoi && !rule->uid_op(cred->uid, rule->uid)) 584139069efSMimi Zohar return false; 5853dd0c8d0SMikhail Kurinnoi } else if (!rule->uid_op(cred->euid, rule->uid)) 586139069efSMimi Zohar return false; 587139069efSMimi Zohar } 58840224c41SCurtis Veit if ((rule->flags & IMA_GID) && !rule->gid_op(cred->gid, rule->gid)) 58940224c41SCurtis Veit return false; 59040224c41SCurtis Veit if (rule->flags & IMA_EGID) { 59140224c41SCurtis Veit if (has_capability_noaudit(current, CAP_SETGID)) { 59240224c41SCurtis Veit if (!rule->gid_op(cred->egid, rule->gid) 59340224c41SCurtis Veit && !rule->gid_op(cred->sgid, rule->gid) 59440224c41SCurtis Veit && !rule->gid_op(cred->gid, rule->gid)) 59540224c41SCurtis Veit return false; 59640224c41SCurtis Veit } else if (!rule->gid_op(cred->egid, rule->gid)) 59740224c41SCurtis Veit return false; 59840224c41SCurtis Veit } 5993dd0c8d0SMikhail Kurinnoi if ((rule->flags & IMA_FOWNER) && 600a2d2329eSChristian Brauner !rule->fowner_op(i_uid_into_mnt(mnt_userns, inode), rule->fowner)) 60107f6a794SMimi Zohar return false; 60240224c41SCurtis Veit if ((rule->flags & IMA_FGROUP) && 60340224c41SCurtis Veit !rule->fgroup_op(i_gid_into_mnt(mnt_userns, inode), rule->fgroup)) 60440224c41SCurtis Veit return false; 6054af4662fSMimi Zohar for (i = 0; i < MAX_LSM_RULES; i++) { 60653fc0e22SMimi Zohar int rc = 0; 607d906c10dSMatthew Garrett u32 osid; 6084af4662fSMimi Zohar 609483ec26eSJanne Karhunen if (!rule->lsm[i].rule) { 610483ec26eSJanne Karhunen if (!rule->lsm[i].args_p) 6114af4662fSMimi Zohar continue; 612483ec26eSJanne Karhunen else 613483ec26eSJanne Karhunen return false; 614483ec26eSJanne Karhunen } 6154af4662fSMimi Zohar switch (i) { 6164af4662fSMimi Zohar case LSM_OBJ_USER: 6174af4662fSMimi Zohar case LSM_OBJ_ROLE: 6184af4662fSMimi Zohar case LSM_OBJ_TYPE: 6194af4662fSMimi Zohar security_inode_getsecid(inode, &osid); 620b8867eedSTyler Hicks rc = ima_filter_rule_match(osid, rule->lsm[i].type, 62153fc0e22SMimi Zohar Audit_equal, 62290462a5bSRichard Guy Briggs rule->lsm[i].rule); 6234af4662fSMimi Zohar break; 6244af4662fSMimi Zohar case LSM_SUBJ_USER: 6254af4662fSMimi Zohar case LSM_SUBJ_ROLE: 6264af4662fSMimi Zohar case LSM_SUBJ_TYPE: 627b8867eedSTyler Hicks rc = ima_filter_rule_match(secid, rule->lsm[i].type, 62853fc0e22SMimi Zohar Audit_equal, 62990462a5bSRichard Guy Briggs rule->lsm[i].rule); 63028073eb0SGustavo A. R. Silva break; 6314af4662fSMimi Zohar default: 6324af4662fSMimi Zohar break; 6334af4662fSMimi Zohar } 6344af4662fSMimi Zohar if (!rc) 6354af4662fSMimi Zohar return false; 6364af4662fSMimi Zohar } 6373323eec9SMimi Zohar return true; 6383323eec9SMimi Zohar } 6393323eec9SMimi Zohar 640d79d72e0SMimi Zohar /* 641d79d72e0SMimi Zohar * In addition to knowing that we need to appraise the file in general, 6425a73fcfaSMimi Zohar * we need to differentiate between calling hooks, for hook specific rules. 643d79d72e0SMimi Zohar */ 6444ad87a3dSMimi Zohar static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) 645d79d72e0SMimi Zohar { 6465a73fcfaSMimi Zohar if (!(rule->flags & IMA_FUNC)) 6475a73fcfaSMimi Zohar return IMA_FILE_APPRAISE; 6485a73fcfaSMimi Zohar 649d79d72e0SMimi Zohar switch (func) { 650d79d72e0SMimi Zohar case MMAP_CHECK: 651d79d72e0SMimi Zohar return IMA_MMAP_APPRAISE; 652d79d72e0SMimi Zohar case BPRM_CHECK: 653d79d72e0SMimi Zohar return IMA_BPRM_APPRAISE; 654d906c10dSMatthew Garrett case CREDS_CHECK: 655d906c10dSMatthew Garrett return IMA_CREDS_APPRAISE; 656d79d72e0SMimi Zohar case FILE_CHECK: 657c6af8efeSMimi Zohar case POST_SETATTR: 658d79d72e0SMimi Zohar return IMA_FILE_APPRAISE; 659c6af8efeSMimi Zohar case MODULE_CHECK ... MAX_CHECK - 1: 660c6af8efeSMimi Zohar default: 661c6af8efeSMimi Zohar return IMA_READ_APPRAISE; 662d79d72e0SMimi Zohar } 663d79d72e0SMimi Zohar } 664d79d72e0SMimi Zohar 6653323eec9SMimi Zohar /** 6663323eec9SMimi Zohar * ima_match_policy - decision based on LSM and other conditions 667a2d2329eSChristian Brauner * @mnt_userns: user namespace of the mount the inode was found from 6683323eec9SMimi Zohar * @inode: pointer to an inode for which the policy decision is being made 669d906c10dSMatthew Garrett * @cred: pointer to a credentials structure for which the policy decision is 670d906c10dSMatthew Garrett * being made 671d906c10dSMatthew Garrett * @secid: LSM secid of the task to be validated 6723323eec9SMimi Zohar * @func: IMA hook identifier 6733323eec9SMimi Zohar * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) 674725de7faSEric Richter * @pcr: set the pcr to extend 67519453ce0SMatthew Garrett * @template_desc: the template that should be used for this rule 6762b4a2474STushar Sugandhi * @func_data: func specific data, may be NULL 6771624dc00STHOBY Simon * @allowed_algos: allowlist of hash algorithms for the IMA xattr 6783323eec9SMimi Zohar * 6793323eec9SMimi Zohar * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) 6803323eec9SMimi Zohar * conditions. 6813323eec9SMimi Zohar * 68238d859f9SPetko Manolov * Since the IMA policy may be updated multiple times we need to lock the 68338d859f9SPetko Manolov * list when walking it. Reads are many orders of magnitude more numerous 68438d859f9SPetko Manolov * than writes so ima_match_policy() is classical RCU candidate. 6853323eec9SMimi Zohar */ 686a2d2329eSChristian Brauner int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, 687a2d2329eSChristian Brauner const struct cred *cred, u32 secid, enum ima_hooks func, 688a2d2329eSChristian Brauner int mask, int flags, int *pcr, 689e9085e0aSLakshmi Ramasubramanian struct ima_template_desc **template_desc, 6901624dc00STHOBY Simon const char *func_data, unsigned int *allowed_algos) 6913323eec9SMimi Zohar { 69207f6a794SMimi Zohar struct ima_rule_entry *entry; 6932fe5d6deSMimi Zohar int action = 0, actmask = flags | (flags << 1); 694eb0782bbSliqiong struct list_head *ima_rules_tmp; 6953323eec9SMimi Zohar 696dea87d08SLakshmi Ramasubramanian if (template_desc && !*template_desc) 697b36f281fSMimi Zohar *template_desc = ima_template_desc_current(); 698b36f281fSMimi Zohar 69938d859f9SPetko Manolov rcu_read_lock(); 700eb0782bbSliqiong ima_rules_tmp = rcu_dereference(ima_rules); 701eb0782bbSliqiong list_for_each_entry_rcu(entry, ima_rules_tmp, list) { 7023323eec9SMimi Zohar 7032fe5d6deSMimi Zohar if (!(entry->action & actmask)) 7042fe5d6deSMimi Zohar continue; 7052fe5d6deSMimi Zohar 706a2d2329eSChristian Brauner if (!ima_match_rules(entry, mnt_userns, inode, cred, secid, 7077d6beb71SLinus Torvalds func, mask, func_data)) 7082fe5d6deSMimi Zohar continue; 7092fe5d6deSMimi Zohar 710aae6ccbdSMimi Zohar action |= entry->flags & IMA_NONACTION_FLAGS; 7110e5a247cSDmitry Kasatkin 71245e2472eSDmitry Kasatkin action |= entry->action & IMA_DO_MASK; 713da1b0029SMimi Zohar if (entry->action & IMA_APPRAISE) { 7145a73fcfaSMimi Zohar action |= get_subaction(entry, func); 715a9a4935dSMimi Zohar action &= ~IMA_HASH; 7169e67028eSMimi Zohar if (ima_fail_unverifiable_sigs) 7179e67028eSMimi Zohar action |= IMA_FAIL_UNVERIFIABLE_SIGS; 718d79d72e0SMimi Zohar 7191624dc00STHOBY Simon if (allowed_algos && 7201624dc00STHOBY Simon entry->flags & IMA_VALIDATE_ALGOS) 7211624dc00STHOBY Simon *allowed_algos = entry->allowed_algos; 7221624dc00STHOBY Simon } 723b36f281fSMimi Zohar 72445e2472eSDmitry Kasatkin if (entry->action & IMA_DO_MASK) 72545e2472eSDmitry Kasatkin actmask &= ~(entry->action | entry->action << 1); 72645e2472eSDmitry Kasatkin else 72745e2472eSDmitry Kasatkin actmask &= ~(entry->action | entry->action >> 1); 72845e2472eSDmitry Kasatkin 729725de7faSEric Richter if ((pcr) && (entry->flags & IMA_PCR)) 730725de7faSEric Richter *pcr = entry->pcr; 731725de7faSEric Richter 73219453ce0SMatthew Garrett if (template_desc && entry->template) 73319453ce0SMatthew Garrett *template_desc = entry->template; 73419453ce0SMatthew Garrett 7352fe5d6deSMimi Zohar if (!actmask) 7362fe5d6deSMimi Zohar break; 7373323eec9SMimi Zohar } 73838d859f9SPetko Manolov rcu_read_unlock(); 7392fe5d6deSMimi Zohar 7402fe5d6deSMimi Zohar return action; 7413323eec9SMimi Zohar } 7423323eec9SMimi Zohar 7434f2946aaSTHOBY Simon /** 7444f2946aaSTHOBY Simon * ima_update_policy_flags() - Update global IMA variables 7454f2946aaSTHOBY Simon * 7464f2946aaSTHOBY Simon * Update ima_policy_flag and ima_setxattr_allowed_hash_algorithms 7474f2946aaSTHOBY Simon * based on the currently loaded policy. 7484f2946aaSTHOBY Simon * 7494f2946aaSTHOBY Simon * With ima_policy_flag, the decision to short circuit out of a function 7504f2946aaSTHOBY Simon * or not call the function in the first place can be made earlier. 7514f2946aaSTHOBY Simon * 7524f2946aaSTHOBY Simon * With ima_setxattr_allowed_hash_algorithms, the policy can restrict the 7534f2946aaSTHOBY Simon * set of hash algorithms accepted when updating the security.ima xattr of 7544f2946aaSTHOBY Simon * a file. 7554f2946aaSTHOBY Simon * 7564f2946aaSTHOBY Simon * Context: called after a policy update and at system initialization. 757a756024eSRoberto Sassu */ 7584f2946aaSTHOBY Simon void ima_update_policy_flags(void) 759a756024eSRoberto Sassu { 760a756024eSRoberto Sassu struct ima_rule_entry *entry; 7614f2946aaSTHOBY Simon int new_policy_flag = 0; 762eb0782bbSliqiong struct list_head *ima_rules_tmp; 763a756024eSRoberto Sassu 7644f2946aaSTHOBY Simon rcu_read_lock(); 765eb0782bbSliqiong ima_rules_tmp = rcu_dereference(ima_rules); 766eb0782bbSliqiong list_for_each_entry_rcu(entry, ima_rules_tmp, list) { 7674f2946aaSTHOBY Simon /* 7684f2946aaSTHOBY Simon * SETXATTR_CHECK rules do not implement a full policy check 7694f2946aaSTHOBY Simon * because rule checking would probably have an important 7704f2946aaSTHOBY Simon * performance impact on setxattr(). As a consequence, only one 7714f2946aaSTHOBY Simon * SETXATTR_CHECK can be active at a given time. 7724f2946aaSTHOBY Simon * Because we want to preserve that property, we set out to use 7734f2946aaSTHOBY Simon * atomic_cmpxchg. Either: 7744f2946aaSTHOBY Simon * - the atomic was non-zero: a setxattr hash policy is 7754f2946aaSTHOBY Simon * already enforced, we do nothing 7764f2946aaSTHOBY Simon * - the atomic was zero: no setxattr policy was set, enable 7774f2946aaSTHOBY Simon * the setxattr hash policy 7784f2946aaSTHOBY Simon */ 7794f2946aaSTHOBY Simon if (entry->func == SETXATTR_CHECK) { 7804f2946aaSTHOBY Simon atomic_cmpxchg(&ima_setxattr_allowed_hash_algorithms, 7814f2946aaSTHOBY Simon 0, entry->allowed_algos); 7824f2946aaSTHOBY Simon /* SETXATTR_CHECK doesn't impact ima_policy_flag */ 7834f2946aaSTHOBY Simon continue; 784a756024eSRoberto Sassu } 785a756024eSRoberto Sassu 7864f2946aaSTHOBY Simon if (entry->action & IMA_DO_MASK) 7874f2946aaSTHOBY Simon new_policy_flag |= entry->action; 7884f2946aaSTHOBY Simon } 7894f2946aaSTHOBY Simon rcu_read_unlock(); 7904f2946aaSTHOBY Simon 791ef96837bSMimi Zohar ima_appraise |= (build_ima_appraise | temp_ima_appraise); 792a756024eSRoberto Sassu if (!ima_appraise) 7934f2946aaSTHOBY Simon new_policy_flag &= ~IMA_APPRAISE; 7944f2946aaSTHOBY Simon 7954f2946aaSTHOBY Simon ima_policy_flag = new_policy_flag; 796a756024eSRoberto Sassu } 797a756024eSRoberto Sassu 7986f0911a6SMimi Zohar static int ima_appraise_flag(enum ima_hooks func) 7996f0911a6SMimi Zohar { 8006f0911a6SMimi Zohar if (func == MODULE_CHECK) 8016f0911a6SMimi Zohar return IMA_APPRAISE_MODULES; 8026f0911a6SMimi Zohar else if (func == FIRMWARE_CHECK) 8036f0911a6SMimi Zohar return IMA_APPRAISE_FIRMWARE; 8046f0911a6SMimi Zohar else if (func == POLICY_CHECK) 8056f0911a6SMimi Zohar return IMA_APPRAISE_POLICY; 80616c267aaSMimi Zohar else if (func == KEXEC_KERNEL_CHECK) 80716c267aaSMimi Zohar return IMA_APPRAISE_KEXEC; 8086f0911a6SMimi Zohar return 0; 8096f0911a6SMimi Zohar } 8106f0911a6SMimi Zohar 811c52657d9SNayna Jain static void add_rules(struct ima_rule_entry *entries, int count, 812c52657d9SNayna Jain enum policy_rule_list policy_rule) 813c52657d9SNayna Jain { 814c52657d9SNayna Jain int i = 0; 815c52657d9SNayna Jain 816c52657d9SNayna Jain for (i = 0; i < count; i++) { 817c52657d9SNayna Jain struct ima_rule_entry *entry; 818c52657d9SNayna Jain 819c52657d9SNayna Jain if (policy_rule & IMA_DEFAULT_POLICY) 820c52657d9SNayna Jain list_add_tail(&entries[i].list, &ima_default_rules); 821c52657d9SNayna Jain 822c52657d9SNayna Jain if (policy_rule & IMA_CUSTOM_POLICY) { 823c52657d9SNayna Jain entry = kmemdup(&entries[i], sizeof(*entry), 824c52657d9SNayna Jain GFP_KERNEL); 825c52657d9SNayna Jain if (!entry) 826c52657d9SNayna Jain continue; 827c52657d9SNayna Jain 828c52657d9SNayna Jain list_add_tail(&entry->list, &ima_policy_rules); 829c52657d9SNayna Jain } 830b59fda44SKrzysztof Struczynski if (entries[i].action == APPRAISE) { 831b59fda44SKrzysztof Struczynski if (entries != build_appraise_rules) 832b59fda44SKrzysztof Struczynski temp_ima_appraise |= 833b59fda44SKrzysztof Struczynski ima_appraise_flag(entries[i].func); 834b59fda44SKrzysztof Struczynski else 835b59fda44SKrzysztof Struczynski build_ima_appraise |= 836b59fda44SKrzysztof Struczynski ima_appraise_flag(entries[i].func); 837b59fda44SKrzysztof Struczynski } 838c52657d9SNayna Jain } 839f4001947SPetr Vorel } 840c52657d9SNayna Jain 84161917062SNayna Jain static int ima_parse_rule(char *rule, struct ima_rule_entry *entry); 84261917062SNayna Jain 84361917062SNayna Jain static int __init ima_init_arch_policy(void) 84461917062SNayna Jain { 84561917062SNayna Jain const char * const *arch_rules; 84661917062SNayna Jain const char * const *rules; 84761917062SNayna Jain int arch_entries = 0; 84861917062SNayna Jain int i = 0; 84961917062SNayna Jain 85061917062SNayna Jain arch_rules = arch_get_ima_policy(); 85161917062SNayna Jain if (!arch_rules) 85261917062SNayna Jain return arch_entries; 85361917062SNayna Jain 85461917062SNayna Jain /* Get number of rules */ 85561917062SNayna Jain for (rules = arch_rules; *rules != NULL; rules++) 85661917062SNayna Jain arch_entries++; 85761917062SNayna Jain 85861917062SNayna Jain arch_policy_entry = kcalloc(arch_entries + 1, 85961917062SNayna Jain sizeof(*arch_policy_entry), GFP_KERNEL); 86061917062SNayna Jain if (!arch_policy_entry) 86161917062SNayna Jain return 0; 86261917062SNayna Jain 86361917062SNayna Jain /* Convert each policy string rules to struct ima_rule_entry format */ 86461917062SNayna Jain for (rules = arch_rules, i = 0; *rules != NULL; rules++) { 86561917062SNayna Jain char rule[255]; 86661917062SNayna Jain int result; 86761917062SNayna Jain 868cc4299eaSPetr Vorel result = strscpy(rule, *rules, sizeof(rule)); 86961917062SNayna Jain 87061917062SNayna Jain INIT_LIST_HEAD(&arch_policy_entry[i].list); 87161917062SNayna Jain result = ima_parse_rule(rule, &arch_policy_entry[i]); 87261917062SNayna Jain if (result) { 87361917062SNayna Jain pr_warn("Skipping unknown architecture policy rule: %s\n", 87461917062SNayna Jain rule); 87561917062SNayna Jain memset(&arch_policy_entry[i], 0, 87661917062SNayna Jain sizeof(*arch_policy_entry)); 87761917062SNayna Jain continue; 87861917062SNayna Jain } 87961917062SNayna Jain i++; 88061917062SNayna Jain } 88161917062SNayna Jain return i; 88261917062SNayna Jain } 88361917062SNayna Jain 8843323eec9SMimi Zohar /** 8853323eec9SMimi Zohar * ima_init_policy - initialize the default measure rules. 8863323eec9SMimi Zohar * 88761868acbSPetr Vorel * ima_rules points to either the ima_default_rules or the new ima_policy_rules. 8883323eec9SMimi Zohar */ 889932995f0SEric Paris void __init ima_init_policy(void) 8903323eec9SMimi Zohar { 89161917062SNayna Jain int build_appraise_entries, arch_entries; 8923323eec9SMimi Zohar 893c52657d9SNayna Jain /* if !ima_policy, we load NO default rules */ 894c52657d9SNayna Jain if (ima_policy) 895c52657d9SNayna Jain add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules), 896c52657d9SNayna Jain IMA_DEFAULT_POLICY); 89724fd03c8SMimi Zohar 89824fd03c8SMimi Zohar switch (ima_policy) { 89924fd03c8SMimi Zohar case ORIGINAL_TCB: 900c52657d9SNayna Jain add_rules(original_measurement_rules, 901c52657d9SNayna Jain ARRAY_SIZE(original_measurement_rules), 902c52657d9SNayna Jain IMA_DEFAULT_POLICY); 90324fd03c8SMimi Zohar break; 90424fd03c8SMimi Zohar case DEFAULT_TCB: 905c52657d9SNayna Jain add_rules(default_measurement_rules, 906c52657d9SNayna Jain ARRAY_SIZE(default_measurement_rules), 907c52657d9SNayna Jain IMA_DEFAULT_POLICY); 90828073eb0SGustavo A. R. Silva break; 90924fd03c8SMimi Zohar default: 91024fd03c8SMimi Zohar break; 91124fd03c8SMimi Zohar } 91207f6a794SMimi Zohar 913503ceaefSMimi Zohar /* 91461917062SNayna Jain * Based on runtime secure boot flags, insert arch specific measurement 91561917062SNayna Jain * and appraise rules requiring file signatures for both the initial 91661917062SNayna Jain * and custom policies, prior to other appraise rules. 91761917062SNayna Jain * (Highest priority) 918503ceaefSMimi Zohar */ 91961917062SNayna Jain arch_entries = ima_init_arch_policy(); 92061917062SNayna Jain if (!arch_entries) 92161917062SNayna Jain pr_info("No architecture policies found\n"); 92261917062SNayna Jain else 92361917062SNayna Jain add_rules(arch_policy_entry, arch_entries, 92461917062SNayna Jain IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); 92561917062SNayna Jain 92661917062SNayna Jain /* 927503ceaefSMimi Zohar * Insert the builtin "secure_boot" policy rules requiring file 92861917062SNayna Jain * signatures, prior to other appraise rules. 929503ceaefSMimi Zohar */ 930c52657d9SNayna Jain if (ima_use_secure_boot) 931c52657d9SNayna Jain add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules), 932c52657d9SNayna Jain IMA_DEFAULT_POLICY); 933503ceaefSMimi Zohar 934ef96837bSMimi Zohar /* 935ef96837bSMimi Zohar * Insert the build time appraise rules requiring file signatures 936ef96837bSMimi Zohar * for both the initial and custom policies, prior to other appraise 937c52657d9SNayna Jain * rules. As the secure boot rules includes all of the build time 938c52657d9SNayna Jain * rules, include either one or the other set of rules, but not both. 939ef96837bSMimi Zohar */ 940c52657d9SNayna Jain build_appraise_entries = ARRAY_SIZE(build_appraise_rules); 941c52657d9SNayna Jain if (build_appraise_entries) { 942c52657d9SNayna Jain if (ima_use_secure_boot) 943c52657d9SNayna Jain add_rules(build_appraise_rules, build_appraise_entries, 944c52657d9SNayna Jain IMA_CUSTOM_POLICY); 945c52657d9SNayna Jain else 946c52657d9SNayna Jain add_rules(build_appraise_rules, build_appraise_entries, 947c52657d9SNayna Jain IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); 948ef96837bSMimi Zohar } 949ef96837bSMimi Zohar 950c52657d9SNayna Jain if (ima_use_appraise_tcb) 951c52657d9SNayna Jain add_rules(default_appraise_rules, 952c52657d9SNayna Jain ARRAY_SIZE(default_appraise_rules), 953c52657d9SNayna Jain IMA_DEFAULT_POLICY); 95407f6a794SMimi Zohar 95503cee168SLakshmi Ramasubramanian if (ima_use_critical_data) 95603cee168SLakshmi Ramasubramanian add_rules(critical_data_rules, 95703cee168SLakshmi Ramasubramanian ARRAY_SIZE(critical_data_rules), 95803cee168SLakshmi Ramasubramanian IMA_DEFAULT_POLICY); 95903cee168SLakshmi Ramasubramanian 9604f2946aaSTHOBY Simon atomic_set(&ima_setxattr_allowed_hash_algorithms, 0); 9614f2946aaSTHOBY Simon 9624f2946aaSTHOBY Simon ima_update_policy_flags(); 9633323eec9SMimi Zohar } 9644af4662fSMimi Zohar 9650112721dSSasha Levin /* Make sure we have a valid policy, at least containing some rules. */ 966c75d8e96SColin Ian King int ima_check_policy(void) 9670112721dSSasha Levin { 9680112721dSSasha Levin if (list_empty(&ima_temp_rules)) 9690112721dSSasha Levin return -EINVAL; 9700112721dSSasha Levin return 0; 9710112721dSSasha Levin } 9720112721dSSasha Levin 9734af4662fSMimi Zohar /** 9744af4662fSMimi Zohar * ima_update_policy - update default_rules with new measure rules 9754af4662fSMimi Zohar * 9764af4662fSMimi Zohar * Called on file .release to update the default rules with a complete new 97738d859f9SPetko Manolov * policy. What we do here is to splice ima_policy_rules and ima_temp_rules so 97838d859f9SPetko Manolov * they make a queue. The policy may be updated multiple times and this is the 97938d859f9SPetko Manolov * RCU updater. 98038d859f9SPetko Manolov * 98138d859f9SPetko Manolov * Policy rules are never deleted so ima_policy_flag gets zeroed only once when 98238d859f9SPetko Manolov * we switch from the default policy to user defined. 9834af4662fSMimi Zohar */ 9844af4662fSMimi Zohar void ima_update_policy(void) 9854af4662fSMimi Zohar { 98653b626f9SPetko Manolov struct list_head *policy = &ima_policy_rules; 98738d859f9SPetko Manolov 98853b626f9SPetko Manolov list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu); 98938d859f9SPetko Manolov 990eb0782bbSliqiong if (ima_rules != (struct list_head __rcu *)policy) { 99138d859f9SPetko Manolov ima_policy_flag = 0; 99261917062SNayna Jain 993eb0782bbSliqiong rcu_assign_pointer(ima_rules, policy); 99461917062SNayna Jain /* 99561917062SNayna Jain * IMA architecture specific policy rules are specified 99661917062SNayna Jain * as strings and converted to an array of ima_entry_rules 99761917062SNayna Jain * on boot. After loading a custom policy, free the 99861917062SNayna Jain * architecture specific rules stored as an array. 99961917062SNayna Jain */ 100061917062SNayna Jain kfree(arch_policy_entry); 100138d859f9SPetko Manolov } 10024f2946aaSTHOBY Simon ima_update_policy_flags(); 1003450d0fd5SLakshmi Ramasubramanian 1004450d0fd5SLakshmi Ramasubramanian /* Custom IMA policy has been loaded */ 1005450d0fd5SLakshmi Ramasubramanian ima_process_queued_keys(); 10064af4662fSMimi Zohar } 10074af4662fSMimi Zohar 10081a9430dbSMimi Zohar /* Keep the enumeration in sync with the policy_tokens! */ 100940224c41SCurtis Veit enum policy_opt { 10101a9430dbSMimi Zohar Opt_measure, Opt_dont_measure, 101107f6a794SMimi Zohar Opt_appraise, Opt_dont_appraise, 1012da1b0029SMimi Zohar Opt_audit, Opt_hash, Opt_dont_hash, 10134af4662fSMimi Zohar Opt_obj_user, Opt_obj_role, Opt_obj_type, 10144af4662fSMimi Zohar Opt_subj_user, Opt_subj_role, Opt_subj_type, 101540224c41SCurtis Veit Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname, Opt_fsuuid, 101640224c41SCurtis Veit Opt_uid_eq, Opt_euid_eq, Opt_gid_eq, Opt_egid_eq, 101740224c41SCurtis Veit Opt_fowner_eq, Opt_fgroup_eq, 101840224c41SCurtis Veit Opt_uid_gt, Opt_euid_gt, Opt_gid_gt, Opt_egid_gt, 101940224c41SCurtis Veit Opt_fowner_gt, Opt_fgroup_gt, 102040224c41SCurtis Veit Opt_uid_lt, Opt_euid_lt, Opt_gid_lt, Opt_egid_lt, 102140224c41SCurtis Veit Opt_fowner_lt, Opt_fgroup_lt, 102254f03916SMimi Zohar Opt_digest_type, 1023583a80aeSTHOBY Simon Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos, 10242b60c0ecSLakshmi Ramasubramanian Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings, 102547d76a48STushar Sugandhi Opt_label, Opt_err 10264af4662fSMimi Zohar }; 10274af4662fSMimi Zohar 10281a9430dbSMimi Zohar static const match_table_t policy_tokens = { 10294af4662fSMimi Zohar {Opt_measure, "measure"}, 10304af4662fSMimi Zohar {Opt_dont_measure, "dont_measure"}, 103107f6a794SMimi Zohar {Opt_appraise, "appraise"}, 103207f6a794SMimi Zohar {Opt_dont_appraise, "dont_appraise"}, 1033e7c568e0SPeter Moody {Opt_audit, "audit"}, 1034da1b0029SMimi Zohar {Opt_hash, "hash"}, 1035da1b0029SMimi Zohar {Opt_dont_hash, "dont_hash"}, 10364af4662fSMimi Zohar {Opt_obj_user, "obj_user=%s"}, 10374af4662fSMimi Zohar {Opt_obj_role, "obj_role=%s"}, 10384af4662fSMimi Zohar {Opt_obj_type, "obj_type=%s"}, 10394af4662fSMimi Zohar {Opt_subj_user, "subj_user=%s"}, 10404af4662fSMimi Zohar {Opt_subj_role, "subj_role=%s"}, 10414af4662fSMimi Zohar {Opt_subj_type, "subj_type=%s"}, 10424af4662fSMimi Zohar {Opt_func, "func=%s"}, 10434af4662fSMimi Zohar {Opt_mask, "mask=%s"}, 10444af4662fSMimi Zohar {Opt_fsmagic, "fsmagic=%s"}, 1045f1b08bbcSMimi Zohar {Opt_fsname, "fsname=%s"}, 104685865c1fSDmitry Kasatkin {Opt_fsuuid, "fsuuid=%s"}, 10473dd0c8d0SMikhail Kurinnoi {Opt_uid_eq, "uid=%s"}, 10483dd0c8d0SMikhail Kurinnoi {Opt_euid_eq, "euid=%s"}, 104940224c41SCurtis Veit {Opt_gid_eq, "gid=%s"}, 105040224c41SCurtis Veit {Opt_egid_eq, "egid=%s"}, 10513dd0c8d0SMikhail Kurinnoi {Opt_fowner_eq, "fowner=%s"}, 105240224c41SCurtis Veit {Opt_fgroup_eq, "fgroup=%s"}, 10533dd0c8d0SMikhail Kurinnoi {Opt_uid_gt, "uid>%s"}, 10543dd0c8d0SMikhail Kurinnoi {Opt_euid_gt, "euid>%s"}, 105540224c41SCurtis Veit {Opt_gid_gt, "gid>%s"}, 105640224c41SCurtis Veit {Opt_egid_gt, "egid>%s"}, 10573dd0c8d0SMikhail Kurinnoi {Opt_fowner_gt, "fowner>%s"}, 105840224c41SCurtis Veit {Opt_fgroup_gt, "fgroup>%s"}, 10593dd0c8d0SMikhail Kurinnoi {Opt_uid_lt, "uid<%s"}, 10603dd0c8d0SMikhail Kurinnoi {Opt_euid_lt, "euid<%s"}, 106140224c41SCurtis Veit {Opt_gid_lt, "gid<%s"}, 106240224c41SCurtis Veit {Opt_egid_lt, "egid<%s"}, 10633dd0c8d0SMikhail Kurinnoi {Opt_fowner_lt, "fowner<%s"}, 106440224c41SCurtis Veit {Opt_fgroup_lt, "fgroup<%s"}, 106554f03916SMimi Zohar {Opt_digest_type, "digest_type=%s"}, 10660e5a247cSDmitry Kasatkin {Opt_appraise_type, "appraise_type=%s"}, 1067273df864SNayna Jain {Opt_appraise_flag, "appraise_flag=%s"}, 1068583a80aeSTHOBY Simon {Opt_appraise_algos, "appraise_algos=%s"}, 1069f9b2a735SMimi Zohar {Opt_permit_directio, "permit_directio"}, 10700260643cSEric Richter {Opt_pcr, "pcr=%s"}, 107119453ce0SMatthew Garrett {Opt_template, "template=%s"}, 10722b60c0ecSLakshmi Ramasubramanian {Opt_keyrings, "keyrings=%s"}, 107347d76a48STushar Sugandhi {Opt_label, "label=%s"}, 10744af4662fSMimi Zohar {Opt_err, NULL} 10754af4662fSMimi Zohar }; 10764af4662fSMimi Zohar 107707f6a794SMimi Zohar static int ima_lsm_rule_init(struct ima_rule_entry *entry, 10787163a993SMimi Zohar substring_t *args, int lsm_rule, int audit_type) 10794af4662fSMimi Zohar { 10804af4662fSMimi Zohar int result; 10814af4662fSMimi Zohar 10827b62e162SEric Paris if (entry->lsm[lsm_rule].rule) 10837b62e162SEric Paris return -EINVAL; 10847b62e162SEric Paris 10857163a993SMimi Zohar entry->lsm[lsm_rule].args_p = match_strdup(args); 10867163a993SMimi Zohar if (!entry->lsm[lsm_rule].args_p) 10877163a993SMimi Zohar return -ENOMEM; 10887163a993SMimi Zohar 10894af4662fSMimi Zohar entry->lsm[lsm_rule].type = audit_type; 1090b8867eedSTyler Hicks result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal, 10917163a993SMimi Zohar entry->lsm[lsm_rule].args_p, 10924af4662fSMimi Zohar &entry->lsm[lsm_rule].rule); 10937163a993SMimi Zohar if (!entry->lsm[lsm_rule].rule) { 1094483ec26eSJanne Karhunen pr_warn("rule for LSM \'%s\' is undefined\n", 1095aa0c0227STyler Hicks entry->lsm[lsm_rule].args_p); 1096483ec26eSJanne Karhunen 1097eb0782bbSliqiong if (ima_rules == (struct list_head __rcu *)(&ima_default_rules)) { 10987163a993SMimi Zohar kfree(entry->lsm[lsm_rule].args_p); 10992bdd737cSTyler Hicks entry->lsm[lsm_rule].args_p = NULL; 1100483ec26eSJanne Karhunen result = -EINVAL; 1101483ec26eSJanne Karhunen } else 1102483ec26eSJanne Karhunen result = 0; 11037163a993SMimi Zohar } 11047163a993SMimi Zohar 11054af4662fSMimi Zohar return result; 11064af4662fSMimi Zohar } 11074af4662fSMimi Zohar 11083dd0c8d0SMikhail Kurinnoi static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value, 110940224c41SCurtis Veit enum policy_opt rule_operator) 11102f1506cdSEric Paris { 11112afd020aSStefan Berger if (!ab) 11122afd020aSStefan Berger return; 11132afd020aSStefan Berger 111440224c41SCurtis Veit switch (rule_operator) { 111540224c41SCurtis Veit case Opt_uid_gt: 111640224c41SCurtis Veit case Opt_euid_gt: 111740224c41SCurtis Veit case Opt_gid_gt: 111840224c41SCurtis Veit case Opt_egid_gt: 111940224c41SCurtis Veit case Opt_fowner_gt: 112040224c41SCurtis Veit case Opt_fgroup_gt: 11213dd0c8d0SMikhail Kurinnoi audit_log_format(ab, "%s>", key); 112240224c41SCurtis Veit break; 112340224c41SCurtis Veit case Opt_uid_lt: 112440224c41SCurtis Veit case Opt_euid_lt: 112540224c41SCurtis Veit case Opt_gid_lt: 112640224c41SCurtis Veit case Opt_egid_lt: 112740224c41SCurtis Veit case Opt_fowner_lt: 112840224c41SCurtis Veit case Opt_fgroup_lt: 11293dd0c8d0SMikhail Kurinnoi audit_log_format(ab, "%s<", key); 113040224c41SCurtis Veit break; 113140224c41SCurtis Veit default: 11322f1506cdSEric Paris audit_log_format(ab, "%s=", key); 113340224c41SCurtis Veit } 11343d2859d5SStefan Berger audit_log_format(ab, "%s ", value); 11352f1506cdSEric Paris } 11363dd0c8d0SMikhail Kurinnoi static void ima_log_string(struct audit_buffer *ab, char *key, char *value) 11373dd0c8d0SMikhail Kurinnoi { 113840224c41SCurtis Veit ima_log_string_op(ab, key, value, Opt_err); 11393dd0c8d0SMikhail Kurinnoi } 11402f1506cdSEric Paris 11413878d505SThiago Jung Bauermann /* 11423878d505SThiago Jung Bauermann * Validating the appended signature included in the measurement list requires 11433878d505SThiago Jung Bauermann * the file hash calculated without the appended signature (i.e., the 'd-modsig' 11443878d505SThiago Jung Bauermann * field). Therefore, notify the user if they have the 'modsig' field but not 11453878d505SThiago Jung Bauermann * the 'd-modsig' field in the template. 11463878d505SThiago Jung Bauermann */ 11473878d505SThiago Jung Bauermann static void check_template_modsig(const struct ima_template_desc *template) 11483878d505SThiago Jung Bauermann { 11493878d505SThiago Jung Bauermann #define MSG "template with 'modsig' field also needs 'd-modsig' field\n" 11503878d505SThiago Jung Bauermann bool has_modsig, has_dmodsig; 11513878d505SThiago Jung Bauermann static bool checked; 11523878d505SThiago Jung Bauermann int i; 11533878d505SThiago Jung Bauermann 11543878d505SThiago Jung Bauermann /* We only need to notify the user once. */ 11553878d505SThiago Jung Bauermann if (checked) 11563878d505SThiago Jung Bauermann return; 11573878d505SThiago Jung Bauermann 11583878d505SThiago Jung Bauermann has_modsig = has_dmodsig = false; 11593878d505SThiago Jung Bauermann for (i = 0; i < template->num_fields; i++) { 11603878d505SThiago Jung Bauermann if (!strcmp(template->fields[i]->field_id, "modsig")) 11613878d505SThiago Jung Bauermann has_modsig = true; 11623878d505SThiago Jung Bauermann else if (!strcmp(template->fields[i]->field_id, "d-modsig")) 11633878d505SThiago Jung Bauermann has_dmodsig = true; 11643878d505SThiago Jung Bauermann } 11653878d505SThiago Jung Bauermann 11663878d505SThiago Jung Bauermann if (has_modsig && !has_dmodsig) 11673878d505SThiago Jung Bauermann pr_notice(MSG); 11683878d505SThiago Jung Bauermann 11693878d505SThiago Jung Bauermann checked = true; 11703878d505SThiago Jung Bauermann #undef MSG 11713878d505SThiago Jung Bauermann } 11723878d505SThiago Jung Bauermann 117354f03916SMimi Zohar /* 117454f03916SMimi Zohar * Warn if the template does not contain the given field. 117554f03916SMimi Zohar */ 117654f03916SMimi Zohar static void check_template_field(const struct ima_template_desc *template, 117754f03916SMimi Zohar const char *field, const char *msg) 117854f03916SMimi Zohar { 117954f03916SMimi Zohar int i; 118054f03916SMimi Zohar 118154f03916SMimi Zohar for (i = 0; i < template->num_fields; i++) 118254f03916SMimi Zohar if (!strcmp(template->fields[i]->field_id, field)) 118354f03916SMimi Zohar return; 118454f03916SMimi Zohar 118554f03916SMimi Zohar pr_notice_once("%s", msg); 118654f03916SMimi Zohar } 118754f03916SMimi Zohar 118871218343STyler Hicks static bool ima_validate_rule(struct ima_rule_entry *entry) 118971218343STyler Hicks { 119030031b0eSTyler Hicks /* Ensure that the action is set and is compatible with the flags */ 119171218343STyler Hicks if (entry->action == UNKNOWN) 119271218343STyler Hicks return false; 119371218343STyler Hicks 119430031b0eSTyler Hicks if (entry->action != MEASURE && entry->flags & IMA_PCR) 119530031b0eSTyler Hicks return false; 119630031b0eSTyler Hicks 119730031b0eSTyler Hicks if (entry->action != APPRAISE && 1198583a80aeSTHOBY Simon entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | 1199583a80aeSTHOBY Simon IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS)) 120030031b0eSTyler Hicks return false; 120130031b0eSTyler Hicks 120230031b0eSTyler Hicks /* 120330031b0eSTyler Hicks * The IMA_FUNC bit must be set if and only if there's a valid hook 120430031b0eSTyler Hicks * function specified, and vice versa. Enforcing this property allows 120530031b0eSTyler Hicks * for the NONE case below to validate a rule without an explicit hook 120630031b0eSTyler Hicks * function. 120730031b0eSTyler Hicks */ 120830031b0eSTyler Hicks if (((entry->flags & IMA_FUNC) && entry->func == NONE) || 120930031b0eSTyler Hicks (!(entry->flags & IMA_FUNC) && entry->func != NONE)) 121030031b0eSTyler Hicks return false; 121130031b0eSTyler Hicks 121271218343STyler Hicks /* 121371218343STyler Hicks * Ensure that the hook function is compatible with the other 121471218343STyler Hicks * components of the rule 121571218343STyler Hicks */ 121671218343STyler Hicks switch (entry->func) { 121771218343STyler Hicks case NONE: 121871218343STyler Hicks case FILE_CHECK: 121971218343STyler Hicks case MMAP_CHECK: 122071218343STyler Hicks case BPRM_CHECK: 122171218343STyler Hicks case CREDS_CHECK: 122271218343STyler Hicks case POST_SETATTR: 122371218343STyler Hicks case FIRMWARE_CHECK: 122430031b0eSTyler Hicks case POLICY_CHECK: 122530031b0eSTyler Hicks if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | 122630031b0eSTyler Hicks IMA_UID | IMA_FOWNER | IMA_FSUUID | 122730031b0eSTyler Hicks IMA_INMASK | IMA_EUID | IMA_PCR | 122840224c41SCurtis Veit IMA_FSNAME | IMA_GID | IMA_EGID | 122940224c41SCurtis Veit IMA_FGROUP | IMA_DIGSIG_REQUIRED | 123054f03916SMimi Zohar IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS | 123154f03916SMimi Zohar IMA_VERITY_REQUIRED)) 123230031b0eSTyler Hicks return false; 123330031b0eSTyler Hicks 123430031b0eSTyler Hicks break; 123530031b0eSTyler Hicks case MODULE_CHECK: 123671218343STyler Hicks case KEXEC_KERNEL_CHECK: 123771218343STyler Hicks case KEXEC_INITRAMFS_CHECK: 123830031b0eSTyler Hicks if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | 123930031b0eSTyler Hicks IMA_UID | IMA_FOWNER | IMA_FSUUID | 124030031b0eSTyler Hicks IMA_INMASK | IMA_EUID | IMA_PCR | 124140224c41SCurtis Veit IMA_FSNAME | IMA_GID | IMA_EGID | 124240224c41SCurtis Veit IMA_FGROUP | IMA_DIGSIG_REQUIRED | 124330031b0eSTyler Hicks IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED | 1244583a80aeSTHOBY Simon IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS)) 124530031b0eSTyler Hicks return false; 124630031b0eSTyler Hicks 124771218343STyler Hicks break; 124871218343STyler Hicks case KEXEC_CMDLINE: 1249db2045f5STyler Hicks if (entry->action & ~(MEASURE | DONT_MEASURE)) 1250db2045f5STyler Hicks return false; 1251db2045f5STyler Hicks 12524834177eSTyler Hicks if (entry->flags & ~(IMA_FUNC | IMA_FSMAGIC | IMA_UID | 12534834177eSTyler Hicks IMA_FOWNER | IMA_FSUUID | IMA_EUID | 125440224c41SCurtis Veit IMA_PCR | IMA_FSNAME | IMA_GID | IMA_EGID | 125540224c41SCurtis Veit IMA_FGROUP)) 1256db2045f5STyler Hicks return false; 1257db2045f5STyler Hicks 1258db2045f5STyler Hicks break; 125971218343STyler Hicks case KEY_CHECK: 126071218343STyler Hicks if (entry->action & ~(MEASURE | DONT_MEASURE)) 126171218343STyler Hicks return false; 126271218343STyler Hicks 126340224c41SCurtis Veit if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR | 1264eb624fe2STyler Hicks IMA_KEYRINGS)) 1265eb624fe2STyler Hicks return false; 1266eb624fe2STyler Hicks 1267eb624fe2STyler Hicks if (ima_rule_contains_lsm_cond(entry)) 1268eb624fe2STyler Hicks return false; 1269eb624fe2STyler Hicks 127071218343STyler Hicks break; 1271c4e43aa2STushar Sugandhi case CRITICAL_DATA: 1272c4e43aa2STushar Sugandhi if (entry->action & ~(MEASURE | DONT_MEASURE)) 1273c4e43aa2STushar Sugandhi return false; 1274c4e43aa2STushar Sugandhi 127540224c41SCurtis Veit if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR | 127647d76a48STushar Sugandhi IMA_LABEL)) 1277c4e43aa2STushar Sugandhi return false; 1278c4e43aa2STushar Sugandhi 1279c4e43aa2STushar Sugandhi if (ima_rule_contains_lsm_cond(entry)) 1280c4e43aa2STushar Sugandhi return false; 1281c4e43aa2STushar Sugandhi 1282c4e43aa2STushar Sugandhi break; 12834f2946aaSTHOBY Simon case SETXATTR_CHECK: 12844f2946aaSTHOBY Simon /* any action other than APPRAISE is unsupported */ 12854f2946aaSTHOBY Simon if (entry->action != APPRAISE) 12864f2946aaSTHOBY Simon return false; 12874f2946aaSTHOBY Simon 12884f2946aaSTHOBY Simon /* SETXATTR_CHECK requires an appraise_algos parameter */ 12894f2946aaSTHOBY Simon if (!(entry->flags & IMA_VALIDATE_ALGOS)) 12904f2946aaSTHOBY Simon return false; 12914f2946aaSTHOBY Simon 12924f2946aaSTHOBY Simon /* 12934f2946aaSTHOBY Simon * full policies are not supported, they would have too 12944f2946aaSTHOBY Simon * much of a performance impact 12954f2946aaSTHOBY Simon */ 12964f2946aaSTHOBY Simon if (entry->flags & ~(IMA_FUNC | IMA_VALIDATE_ALGOS)) 12974f2946aaSTHOBY Simon return false; 12984f2946aaSTHOBY Simon 12994f2946aaSTHOBY Simon break; 130071218343STyler Hicks default: 130171218343STyler Hicks return false; 130271218343STyler Hicks } 130371218343STyler Hicks 13045f3e9265STyler Hicks /* Ensure that combinations of flags are compatible with each other */ 13055f3e9265STyler Hicks if (entry->flags & IMA_CHECK_BLACKLIST && 13065f3e9265STyler Hicks !(entry->flags & IMA_MODSIG_ALLOWED)) 13075f3e9265STyler Hicks return false; 13085f3e9265STyler Hicks 1309398c42e2SMimi Zohar /* 1310398c42e2SMimi Zohar * Unlike for regular IMA 'appraise' policy rules where security.ima 1311398c42e2SMimi Zohar * xattr may contain either a file hash or signature, the security.ima 1312398c42e2SMimi Zohar * xattr for fsverity must contain a file signature (sigv3). Ensure 1313398c42e2SMimi Zohar * that 'appraise' rules for fsverity require file signatures by 1314398c42e2SMimi Zohar * checking the IMA_DIGSIG_REQUIRED flag is set. 1315398c42e2SMimi Zohar */ 1316398c42e2SMimi Zohar if (entry->action == APPRAISE && 1317398c42e2SMimi Zohar (entry->flags & IMA_VERITY_REQUIRED) && 1318398c42e2SMimi Zohar !(entry->flags & IMA_DIGSIG_REQUIRED)) 1319398c42e2SMimi Zohar return false; 1320398c42e2SMimi Zohar 132171218343STyler Hicks return true; 132271218343STyler Hicks } 132371218343STyler Hicks 1324583a80aeSTHOBY Simon static unsigned int ima_parse_appraise_algos(char *arg) 1325583a80aeSTHOBY Simon { 1326583a80aeSTHOBY Simon unsigned int res = 0; 1327583a80aeSTHOBY Simon int idx; 1328583a80aeSTHOBY Simon char *token; 1329583a80aeSTHOBY Simon 1330583a80aeSTHOBY Simon while ((token = strsep(&arg, ",")) != NULL) { 1331583a80aeSTHOBY Simon idx = match_string(hash_algo_name, HASH_ALGO__LAST, token); 1332583a80aeSTHOBY Simon 1333583a80aeSTHOBY Simon if (idx < 0) { 1334583a80aeSTHOBY Simon pr_err("unknown hash algorithm \"%s\"", 1335583a80aeSTHOBY Simon token); 1336583a80aeSTHOBY Simon return 0; 1337583a80aeSTHOBY Simon } 1338583a80aeSTHOBY Simon 13398ecd39cbSTHOBY Simon if (!crypto_has_alg(hash_algo_name[idx], 0, 0)) { 13408ecd39cbSTHOBY Simon pr_err("unavailable hash algorithm \"%s\", check your kernel configuration", 13418ecd39cbSTHOBY Simon token); 13428ecd39cbSTHOBY Simon return 0; 13438ecd39cbSTHOBY Simon } 13448ecd39cbSTHOBY Simon 1345583a80aeSTHOBY Simon /* Add the hash algorithm to the 'allowed' bitfield */ 1346583a80aeSTHOBY Simon res |= (1U << idx); 1347583a80aeSTHOBY Simon } 1348583a80aeSTHOBY Simon 1349583a80aeSTHOBY Simon return res; 1350583a80aeSTHOBY Simon } 1351583a80aeSTHOBY Simon 135207f6a794SMimi Zohar static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) 13534af4662fSMimi Zohar { 13544af4662fSMimi Zohar struct audit_buffer *ab; 13554351c294SMimi Zohar char *from; 13564af4662fSMimi Zohar char *p; 135740224c41SCurtis Veit bool eid_token; /* either euid or egid */ 135819453ce0SMatthew Garrett struct ima_template_desc *template_desc; 13594af4662fSMimi Zohar int result = 0; 13604af4662fSMimi Zohar 1361dba31ee7SStefan Berger ab = integrity_audit_log_start(audit_context(), GFP_KERNEL, 1362dba31ee7SStefan Berger AUDIT_INTEGRITY_POLICY_RULE); 13634af4662fSMimi Zohar 13648b94eea4SEric W. Biederman entry->uid = INVALID_UID; 136540224c41SCurtis Veit entry->gid = INVALID_GID; 136688265322SLinus Torvalds entry->fowner = INVALID_UID; 136740224c41SCurtis Veit entry->fgroup = INVALID_GID; 13683dd0c8d0SMikhail Kurinnoi entry->uid_op = &uid_eq; 136940224c41SCurtis Veit entry->gid_op = &gid_eq; 13703dd0c8d0SMikhail Kurinnoi entry->fowner_op = &uid_eq; 137140224c41SCurtis Veit entry->fgroup_op = &gid_eq; 1372b9035b1fSEric Paris entry->action = UNKNOWN; 137328ef4002SEric Paris while ((p = strsep(&rule, " \t")) != NULL) { 13744af4662fSMimi Zohar substring_t args[MAX_OPT_ARGS]; 13754af4662fSMimi Zohar int token; 13764af4662fSMimi Zohar unsigned long lnum; 13774af4662fSMimi Zohar 13784af4662fSMimi Zohar if (result < 0) 13794af4662fSMimi Zohar break; 138028ef4002SEric Paris if ((*p == '\0') || (*p == ' ') || (*p == '\t')) 138128ef4002SEric Paris continue; 13824af4662fSMimi Zohar token = match_token(p, policy_tokens, args); 13834af4662fSMimi Zohar switch (token) { 13844af4662fSMimi Zohar case Opt_measure: 13852f1506cdSEric Paris ima_log_string(ab, "action", "measure"); 13867b62e162SEric Paris 13877b62e162SEric Paris if (entry->action != UNKNOWN) 13887b62e162SEric Paris result = -EINVAL; 13897b62e162SEric Paris 13904af4662fSMimi Zohar entry->action = MEASURE; 13914af4662fSMimi Zohar break; 13924af4662fSMimi Zohar case Opt_dont_measure: 13932f1506cdSEric Paris ima_log_string(ab, "action", "dont_measure"); 13947b62e162SEric Paris 13957b62e162SEric Paris if (entry->action != UNKNOWN) 13967b62e162SEric Paris result = -EINVAL; 13977b62e162SEric Paris 13984af4662fSMimi Zohar entry->action = DONT_MEASURE; 13994af4662fSMimi Zohar break; 140007f6a794SMimi Zohar case Opt_appraise: 140107f6a794SMimi Zohar ima_log_string(ab, "action", "appraise"); 140207f6a794SMimi Zohar 140307f6a794SMimi Zohar if (entry->action != UNKNOWN) 140407f6a794SMimi Zohar result = -EINVAL; 140507f6a794SMimi Zohar 140607f6a794SMimi Zohar entry->action = APPRAISE; 140707f6a794SMimi Zohar break; 140807f6a794SMimi Zohar case Opt_dont_appraise: 140907f6a794SMimi Zohar ima_log_string(ab, "action", "dont_appraise"); 141007f6a794SMimi Zohar 141107f6a794SMimi Zohar if (entry->action != UNKNOWN) 141207f6a794SMimi Zohar result = -EINVAL; 141307f6a794SMimi Zohar 141407f6a794SMimi Zohar entry->action = DONT_APPRAISE; 141507f6a794SMimi Zohar break; 1416e7c568e0SPeter Moody case Opt_audit: 1417e7c568e0SPeter Moody ima_log_string(ab, "action", "audit"); 1418e7c568e0SPeter Moody 1419e7c568e0SPeter Moody if (entry->action != UNKNOWN) 1420e7c568e0SPeter Moody result = -EINVAL; 1421e7c568e0SPeter Moody 1422e7c568e0SPeter Moody entry->action = AUDIT; 1423e7c568e0SPeter Moody break; 1424da1b0029SMimi Zohar case Opt_hash: 1425da1b0029SMimi Zohar ima_log_string(ab, "action", "hash"); 1426da1b0029SMimi Zohar 1427da1b0029SMimi Zohar if (entry->action != UNKNOWN) 1428da1b0029SMimi Zohar result = -EINVAL; 1429da1b0029SMimi Zohar 1430da1b0029SMimi Zohar entry->action = HASH; 1431da1b0029SMimi Zohar break; 1432da1b0029SMimi Zohar case Opt_dont_hash: 1433da1b0029SMimi Zohar ima_log_string(ab, "action", "dont_hash"); 1434da1b0029SMimi Zohar 1435da1b0029SMimi Zohar if (entry->action != UNKNOWN) 1436da1b0029SMimi Zohar result = -EINVAL; 1437da1b0029SMimi Zohar 1438da1b0029SMimi Zohar entry->action = DONT_HASH; 1439da1b0029SMimi Zohar break; 14404af4662fSMimi Zohar case Opt_func: 14412f1506cdSEric Paris ima_log_string(ab, "func", args[0].from); 14427b62e162SEric Paris 14437b62e162SEric Paris if (entry->func) 14447b62e162SEric Paris result = -EINVAL; 14457b62e162SEric Paris 14461e93d005SMimi Zohar if (strcmp(args[0].from, "FILE_CHECK") == 0) 14471e93d005SMimi Zohar entry->func = FILE_CHECK; 14481e93d005SMimi Zohar /* PATH_CHECK is for backwards compat */ 14491e93d005SMimi Zohar else if (strcmp(args[0].from, "PATH_CHECK") == 0) 14501e93d005SMimi Zohar entry->func = FILE_CHECK; 1451fdf90729SMimi Zohar else if (strcmp(args[0].from, "MODULE_CHECK") == 0) 1452fdf90729SMimi Zohar entry->func = MODULE_CHECK; 14535a9196d7SMimi Zohar else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0) 14545a9196d7SMimi Zohar entry->func = FIRMWARE_CHECK; 145516cac49fSMimi Zohar else if ((strcmp(args[0].from, "FILE_MMAP") == 0) 145616cac49fSMimi Zohar || (strcmp(args[0].from, "MMAP_CHECK") == 0)) 145716cac49fSMimi Zohar entry->func = MMAP_CHECK; 14584af4662fSMimi Zohar else if (strcmp(args[0].from, "BPRM_CHECK") == 0) 14594af4662fSMimi Zohar entry->func = BPRM_CHECK; 1460d906c10dSMatthew Garrett else if (strcmp(args[0].from, "CREDS_CHECK") == 0) 1461d906c10dSMatthew Garrett entry->func = CREDS_CHECK; 1462d9ddf077SMimi Zohar else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") == 1463d9ddf077SMimi Zohar 0) 1464d9ddf077SMimi Zohar entry->func = KEXEC_KERNEL_CHECK; 1465d9ddf077SMimi Zohar else if (strcmp(args[0].from, "KEXEC_INITRAMFS_CHECK") 1466d9ddf077SMimi Zohar == 0) 1467d9ddf077SMimi Zohar entry->func = KEXEC_INITRAMFS_CHECK; 146819f8a847SMimi Zohar else if (strcmp(args[0].from, "POLICY_CHECK") == 0) 146919f8a847SMimi Zohar entry->func = POLICY_CHECK; 1470b0935123SPrakhar Srivastava else if (strcmp(args[0].from, "KEXEC_CMDLINE") == 0) 1471b0935123SPrakhar Srivastava entry->func = KEXEC_CMDLINE; 147248ce1ddcSTyler Hicks else if (IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) && 147348ce1ddcSTyler Hicks strcmp(args[0].from, "KEY_CHECK") == 0) 14745808611cSLakshmi Ramasubramanian entry->func = KEY_CHECK; 1475c4e43aa2STushar Sugandhi else if (strcmp(args[0].from, "CRITICAL_DATA") == 0) 1476c4e43aa2STushar Sugandhi entry->func = CRITICAL_DATA; 14774f2946aaSTHOBY Simon else if (strcmp(args[0].from, "SETXATTR_CHECK") == 0) 14784f2946aaSTHOBY Simon entry->func = SETXATTR_CHECK; 14794af4662fSMimi Zohar else 14804af4662fSMimi Zohar result = -EINVAL; 14814af4662fSMimi Zohar if (!result) 14824af4662fSMimi Zohar entry->flags |= IMA_FUNC; 14834af4662fSMimi Zohar break; 14844af4662fSMimi Zohar case Opt_mask: 14852f1506cdSEric Paris ima_log_string(ab, "mask", args[0].from); 14867b62e162SEric Paris 14877b62e162SEric Paris if (entry->mask) 14887b62e162SEric Paris result = -EINVAL; 14897b62e162SEric Paris 14904351c294SMimi Zohar from = args[0].from; 14914351c294SMimi Zohar if (*from == '^') 14924351c294SMimi Zohar from++; 14934351c294SMimi Zohar 14944351c294SMimi Zohar if ((strcmp(from, "MAY_EXEC")) == 0) 14954af4662fSMimi Zohar entry->mask = MAY_EXEC; 14964351c294SMimi Zohar else if (strcmp(from, "MAY_WRITE") == 0) 14974af4662fSMimi Zohar entry->mask = MAY_WRITE; 14984351c294SMimi Zohar else if (strcmp(from, "MAY_READ") == 0) 14994af4662fSMimi Zohar entry->mask = MAY_READ; 15004351c294SMimi Zohar else if (strcmp(from, "MAY_APPEND") == 0) 15014af4662fSMimi Zohar entry->mask = MAY_APPEND; 15024af4662fSMimi Zohar else 15034af4662fSMimi Zohar result = -EINVAL; 15044af4662fSMimi Zohar if (!result) 15054351c294SMimi Zohar entry->flags |= (*args[0].from == '^') 15064351c294SMimi Zohar ? IMA_INMASK : IMA_MASK; 15074af4662fSMimi Zohar break; 15084af4662fSMimi Zohar case Opt_fsmagic: 15092f1506cdSEric Paris ima_log_string(ab, "fsmagic", args[0].from); 15107b62e162SEric Paris 15117b62e162SEric Paris if (entry->fsmagic) { 15127b62e162SEric Paris result = -EINVAL; 15137b62e162SEric Paris break; 15147b62e162SEric Paris } 15157b62e162SEric Paris 15162bb930abSDmitry Kasatkin result = kstrtoul(args[0].from, 16, &entry->fsmagic); 15174af4662fSMimi Zohar if (!result) 15184af4662fSMimi Zohar entry->flags |= IMA_FSMAGIC; 15194af4662fSMimi Zohar break; 1520f1b08bbcSMimi Zohar case Opt_fsname: 1521f1b08bbcSMimi Zohar ima_log_string(ab, "fsname", args[0].from); 1522f1b08bbcSMimi Zohar 1523f1b08bbcSMimi Zohar entry->fsname = kstrdup(args[0].from, GFP_KERNEL); 1524f1b08bbcSMimi Zohar if (!entry->fsname) { 1525f1b08bbcSMimi Zohar result = -ENOMEM; 1526f1b08bbcSMimi Zohar break; 1527f1b08bbcSMimi Zohar } 1528f1b08bbcSMimi Zohar result = 0; 1529f1b08bbcSMimi Zohar entry->flags |= IMA_FSNAME; 1530f1b08bbcSMimi Zohar break; 15312b60c0ecSLakshmi Ramasubramanian case Opt_keyrings: 15322b60c0ecSLakshmi Ramasubramanian ima_log_string(ab, "keyrings", args[0].from); 15332b60c0ecSLakshmi Ramasubramanian 153448ce1ddcSTyler Hicks if (!IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) || 153548ce1ddcSTyler Hicks entry->keyrings) { 15362b60c0ecSLakshmi Ramasubramanian result = -EINVAL; 15372b60c0ecSLakshmi Ramasubramanian break; 15382b60c0ecSLakshmi Ramasubramanian } 15395c7bac9fSLakshmi Ramasubramanian 1540176377d9STyler Hicks entry->keyrings = ima_alloc_rule_opt_list(args); 1541176377d9STyler Hicks if (IS_ERR(entry->keyrings)) { 1542176377d9STyler Hicks result = PTR_ERR(entry->keyrings); 1543176377d9STyler Hicks entry->keyrings = NULL; 15445c7bac9fSLakshmi Ramasubramanian break; 15455c7bac9fSLakshmi Ramasubramanian } 15465c7bac9fSLakshmi Ramasubramanian 15472b60c0ecSLakshmi Ramasubramanian entry->flags |= IMA_KEYRINGS; 15482b60c0ecSLakshmi Ramasubramanian break; 154947d76a48STushar Sugandhi case Opt_label: 155047d76a48STushar Sugandhi ima_log_string(ab, "label", args[0].from); 155147d76a48STushar Sugandhi 155247d76a48STushar Sugandhi if (entry->label) { 155347d76a48STushar Sugandhi result = -EINVAL; 155447d76a48STushar Sugandhi break; 155547d76a48STushar Sugandhi } 155647d76a48STushar Sugandhi 155747d76a48STushar Sugandhi entry->label = ima_alloc_rule_opt_list(args); 155847d76a48STushar Sugandhi if (IS_ERR(entry->label)) { 155947d76a48STushar Sugandhi result = PTR_ERR(entry->label); 156047d76a48STushar Sugandhi entry->label = NULL; 156147d76a48STushar Sugandhi break; 156247d76a48STushar Sugandhi } 156347d76a48STushar Sugandhi 156447d76a48STushar Sugandhi entry->flags |= IMA_LABEL; 156547d76a48STushar Sugandhi break; 156685865c1fSDmitry Kasatkin case Opt_fsuuid: 156785865c1fSDmitry Kasatkin ima_log_string(ab, "fsuuid", args[0].from); 156885865c1fSDmitry Kasatkin 156936447456SMike Rapoport if (!uuid_is_null(&entry->fsuuid)) { 157085865c1fSDmitry Kasatkin result = -EINVAL; 157185865c1fSDmitry Kasatkin break; 157285865c1fSDmitry Kasatkin } 157385865c1fSDmitry Kasatkin 1574787d8c53SChristoph Hellwig result = uuid_parse(args[0].from, &entry->fsuuid); 1575446d64e3SMimi Zohar if (!result) 157685865c1fSDmitry Kasatkin entry->flags |= IMA_FSUUID; 157785865c1fSDmitry Kasatkin break; 15783dd0c8d0SMikhail Kurinnoi case Opt_uid_gt: 15793dd0c8d0SMikhail Kurinnoi case Opt_euid_gt: 15803dd0c8d0SMikhail Kurinnoi entry->uid_op = &uid_gt; 1581df561f66SGustavo A. R. Silva fallthrough; 15823dd0c8d0SMikhail Kurinnoi case Opt_uid_lt: 15833dd0c8d0SMikhail Kurinnoi case Opt_euid_lt: 15843dd0c8d0SMikhail Kurinnoi if ((token == Opt_uid_lt) || (token == Opt_euid_lt)) 15853dd0c8d0SMikhail Kurinnoi entry->uid_op = &uid_lt; 1586df561f66SGustavo A. R. Silva fallthrough; 15873dd0c8d0SMikhail Kurinnoi case Opt_uid_eq: 15883dd0c8d0SMikhail Kurinnoi case Opt_euid_eq: 158940224c41SCurtis Veit eid_token = (token == Opt_euid_eq) || 159040224c41SCurtis Veit (token == Opt_euid_gt) || 159140224c41SCurtis Veit (token == Opt_euid_lt); 15923dd0c8d0SMikhail Kurinnoi 159340224c41SCurtis Veit ima_log_string_op(ab, eid_token ? "euid" : "uid", 159440224c41SCurtis Veit args[0].from, token); 15957b62e162SEric Paris 15968b94eea4SEric W. Biederman if (uid_valid(entry->uid)) { 15977b62e162SEric Paris result = -EINVAL; 15987b62e162SEric Paris break; 15997b62e162SEric Paris } 16007b62e162SEric Paris 160129707b20SJingoo Han result = kstrtoul(args[0].from, 10, &lnum); 16024af4662fSMimi Zohar if (!result) { 1603139069efSMimi Zohar entry->uid = make_kuid(current_user_ns(), 1604139069efSMimi Zohar (uid_t) lnum); 1605139069efSMimi Zohar if (!uid_valid(entry->uid) || 1606139069efSMimi Zohar (uid_t)lnum != lnum) 16074af4662fSMimi Zohar result = -EINVAL; 16084af4662fSMimi Zohar else 160940224c41SCurtis Veit entry->flags |= eid_token 161040224c41SCurtis Veit ? IMA_EUID : IMA_UID; 161140224c41SCurtis Veit } 161240224c41SCurtis Veit break; 161340224c41SCurtis Veit case Opt_gid_gt: 161440224c41SCurtis Veit case Opt_egid_gt: 161540224c41SCurtis Veit entry->gid_op = &gid_gt; 161640224c41SCurtis Veit fallthrough; 161740224c41SCurtis Veit case Opt_gid_lt: 161840224c41SCurtis Veit case Opt_egid_lt: 161940224c41SCurtis Veit if ((token == Opt_gid_lt) || (token == Opt_egid_lt)) 162040224c41SCurtis Veit entry->gid_op = &gid_lt; 162140224c41SCurtis Veit fallthrough; 162240224c41SCurtis Veit case Opt_gid_eq: 162340224c41SCurtis Veit case Opt_egid_eq: 162440224c41SCurtis Veit eid_token = (token == Opt_egid_eq) || 162540224c41SCurtis Veit (token == Opt_egid_gt) || 162640224c41SCurtis Veit (token == Opt_egid_lt); 162740224c41SCurtis Veit 162840224c41SCurtis Veit ima_log_string_op(ab, eid_token ? "egid" : "gid", 162940224c41SCurtis Veit args[0].from, token); 163040224c41SCurtis Veit 163140224c41SCurtis Veit if (gid_valid(entry->gid)) { 163240224c41SCurtis Veit result = -EINVAL; 163340224c41SCurtis Veit break; 163440224c41SCurtis Veit } 163540224c41SCurtis Veit 163640224c41SCurtis Veit result = kstrtoul(args[0].from, 10, &lnum); 163740224c41SCurtis Veit if (!result) { 163840224c41SCurtis Veit entry->gid = make_kgid(current_user_ns(), 163940224c41SCurtis Veit (gid_t)lnum); 164040224c41SCurtis Veit if (!gid_valid(entry->gid) || 164140224c41SCurtis Veit (((gid_t)lnum) != lnum)) 164240224c41SCurtis Veit result = -EINVAL; 164340224c41SCurtis Veit else 164440224c41SCurtis Veit entry->flags |= eid_token 164540224c41SCurtis Veit ? IMA_EGID : IMA_GID; 16464af4662fSMimi Zohar } 16474af4662fSMimi Zohar break; 16483dd0c8d0SMikhail Kurinnoi case Opt_fowner_gt: 16493dd0c8d0SMikhail Kurinnoi entry->fowner_op = &uid_gt; 1650df561f66SGustavo A. R. Silva fallthrough; 16513dd0c8d0SMikhail Kurinnoi case Opt_fowner_lt: 16523dd0c8d0SMikhail Kurinnoi if (token == Opt_fowner_lt) 16533dd0c8d0SMikhail Kurinnoi entry->fowner_op = &uid_lt; 1654df561f66SGustavo A. R. Silva fallthrough; 16553dd0c8d0SMikhail Kurinnoi case Opt_fowner_eq: 165640224c41SCurtis Veit ima_log_string_op(ab, "fowner", args[0].from, token); 165707f6a794SMimi Zohar 165888265322SLinus Torvalds if (uid_valid(entry->fowner)) { 165907f6a794SMimi Zohar result = -EINVAL; 166007f6a794SMimi Zohar break; 166107f6a794SMimi Zohar } 166207f6a794SMimi Zohar 166329707b20SJingoo Han result = kstrtoul(args[0].from, 10, &lnum); 166407f6a794SMimi Zohar if (!result) { 166530d8764aSAlex Henrie entry->fowner = make_kuid(current_user_ns(), 166630d8764aSAlex Henrie (uid_t)lnum); 166730d8764aSAlex Henrie if (!uid_valid(entry->fowner) || 166830d8764aSAlex Henrie (((uid_t)lnum) != lnum)) 166907f6a794SMimi Zohar result = -EINVAL; 167007f6a794SMimi Zohar else 167107f6a794SMimi Zohar entry->flags |= IMA_FOWNER; 167207f6a794SMimi Zohar } 167307f6a794SMimi Zohar break; 167440224c41SCurtis Veit case Opt_fgroup_gt: 167540224c41SCurtis Veit entry->fgroup_op = &gid_gt; 167640224c41SCurtis Veit fallthrough; 167740224c41SCurtis Veit case Opt_fgroup_lt: 167840224c41SCurtis Veit if (token == Opt_fgroup_lt) 167940224c41SCurtis Veit entry->fgroup_op = &gid_lt; 168040224c41SCurtis Veit fallthrough; 168140224c41SCurtis Veit case Opt_fgroup_eq: 168240224c41SCurtis Veit ima_log_string_op(ab, "fgroup", args[0].from, token); 168340224c41SCurtis Veit 168440224c41SCurtis Veit if (gid_valid(entry->fgroup)) { 168540224c41SCurtis Veit result = -EINVAL; 168640224c41SCurtis Veit break; 168740224c41SCurtis Veit } 168840224c41SCurtis Veit 168940224c41SCurtis Veit result = kstrtoul(args[0].from, 10, &lnum); 169040224c41SCurtis Veit if (!result) { 169140224c41SCurtis Veit entry->fgroup = make_kgid(current_user_ns(), 169240224c41SCurtis Veit (gid_t)lnum); 169340224c41SCurtis Veit if (!gid_valid(entry->fgroup) || 169440224c41SCurtis Veit (((gid_t)lnum) != lnum)) 169540224c41SCurtis Veit result = -EINVAL; 169640224c41SCurtis Veit else 169740224c41SCurtis Veit entry->flags |= IMA_FGROUP; 169840224c41SCurtis Veit } 169940224c41SCurtis Veit break; 17004af4662fSMimi Zohar case Opt_obj_user: 17012f1506cdSEric Paris ima_log_string(ab, "obj_user", args[0].from); 17027163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17034af4662fSMimi Zohar LSM_OBJ_USER, 17044af4662fSMimi Zohar AUDIT_OBJ_USER); 17054af4662fSMimi Zohar break; 17064af4662fSMimi Zohar case Opt_obj_role: 17072f1506cdSEric Paris ima_log_string(ab, "obj_role", args[0].from); 17087163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17094af4662fSMimi Zohar LSM_OBJ_ROLE, 17104af4662fSMimi Zohar AUDIT_OBJ_ROLE); 17114af4662fSMimi Zohar break; 17124af4662fSMimi Zohar case Opt_obj_type: 17132f1506cdSEric Paris ima_log_string(ab, "obj_type", args[0].from); 17147163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17154af4662fSMimi Zohar LSM_OBJ_TYPE, 17164af4662fSMimi Zohar AUDIT_OBJ_TYPE); 17174af4662fSMimi Zohar break; 17184af4662fSMimi Zohar case Opt_subj_user: 17192f1506cdSEric Paris ima_log_string(ab, "subj_user", args[0].from); 17207163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17214af4662fSMimi Zohar LSM_SUBJ_USER, 17224af4662fSMimi Zohar AUDIT_SUBJ_USER); 17234af4662fSMimi Zohar break; 17244af4662fSMimi Zohar case Opt_subj_role: 17252f1506cdSEric Paris ima_log_string(ab, "subj_role", args[0].from); 17267163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17274af4662fSMimi Zohar LSM_SUBJ_ROLE, 17284af4662fSMimi Zohar AUDIT_SUBJ_ROLE); 17294af4662fSMimi Zohar break; 17304af4662fSMimi Zohar case Opt_subj_type: 17312f1506cdSEric Paris ima_log_string(ab, "subj_type", args[0].from); 17327163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17334af4662fSMimi Zohar LSM_SUBJ_TYPE, 17344af4662fSMimi Zohar AUDIT_SUBJ_TYPE); 17354af4662fSMimi Zohar break; 173654f03916SMimi Zohar case Opt_digest_type: 173754f03916SMimi Zohar ima_log_string(ab, "digest_type", args[0].from); 1738398c42e2SMimi Zohar if (entry->flags & IMA_DIGSIG_REQUIRED) 1739398c42e2SMimi Zohar result = -EINVAL; 1740398c42e2SMimi Zohar else if ((strcmp(args[0].from, "verity")) == 0) 174154f03916SMimi Zohar entry->flags |= IMA_VERITY_REQUIRED; 174254f03916SMimi Zohar else 174354f03916SMimi Zohar result = -EINVAL; 174454f03916SMimi Zohar break; 17450e5a247cSDmitry Kasatkin case Opt_appraise_type: 17460e5a247cSDmitry Kasatkin ima_log_string(ab, "appraise_type", args[0].from); 1747398c42e2SMimi Zohar 1748398c42e2SMimi Zohar if ((strcmp(args[0].from, "imasig")) == 0) { 1749398c42e2SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 1750398c42e2SMimi Zohar result = -EINVAL; 1751398c42e2SMimi Zohar else 17520e5a247cSDmitry Kasatkin entry->flags |= IMA_DIGSIG_REQUIRED; 1753398c42e2SMimi Zohar } else if (strcmp(args[0].from, "sigv3") == 0) { 1754398c42e2SMimi Zohar /* Only fsverity supports sigv3 for now */ 1755398c42e2SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 1756398c42e2SMimi Zohar entry->flags |= IMA_DIGSIG_REQUIRED; 17570e5a247cSDmitry Kasatkin else 17580e5a247cSDmitry Kasatkin result = -EINVAL; 1759398c42e2SMimi Zohar } else if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) && 1760398c42e2SMimi Zohar strcmp(args[0].from, "imasig|modsig") == 0) { 1761398c42e2SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 1762398c42e2SMimi Zohar result = -EINVAL; 1763398c42e2SMimi Zohar else 1764398c42e2SMimi Zohar entry->flags |= IMA_DIGSIG_REQUIRED | 1765398c42e2SMimi Zohar IMA_MODSIG_ALLOWED; 1766398c42e2SMimi Zohar } else { 1767398c42e2SMimi Zohar result = -EINVAL; 1768398c42e2SMimi Zohar } 17690e5a247cSDmitry Kasatkin break; 1770273df864SNayna Jain case Opt_appraise_flag: 1771273df864SNayna Jain ima_log_string(ab, "appraise_flag", args[0].from); 17725f3e9265STyler Hicks if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) && 17735f3e9265STyler Hicks strstr(args[0].from, "blacklist")) 1774273df864SNayna Jain entry->flags |= IMA_CHECK_BLACKLIST; 17755f3e9265STyler Hicks else 17765f3e9265STyler Hicks result = -EINVAL; 1777273df864SNayna Jain break; 1778583a80aeSTHOBY Simon case Opt_appraise_algos: 1779583a80aeSTHOBY Simon ima_log_string(ab, "appraise_algos", args[0].from); 1780583a80aeSTHOBY Simon 1781583a80aeSTHOBY Simon if (entry->allowed_algos) { 1782583a80aeSTHOBY Simon result = -EINVAL; 1783583a80aeSTHOBY Simon break; 1784583a80aeSTHOBY Simon } 1785583a80aeSTHOBY Simon 1786583a80aeSTHOBY Simon entry->allowed_algos = 1787583a80aeSTHOBY Simon ima_parse_appraise_algos(args[0].from); 1788583a80aeSTHOBY Simon /* invalid or empty list of algorithms */ 1789583a80aeSTHOBY Simon if (!entry->allowed_algos) { 1790583a80aeSTHOBY Simon result = -EINVAL; 1791583a80aeSTHOBY Simon break; 1792583a80aeSTHOBY Simon } 1793583a80aeSTHOBY Simon 1794583a80aeSTHOBY Simon entry->flags |= IMA_VALIDATE_ALGOS; 1795583a80aeSTHOBY Simon 1796583a80aeSTHOBY Simon break; 1797f9b2a735SMimi Zohar case Opt_permit_directio: 1798f9b2a735SMimi Zohar entry->flags |= IMA_PERMIT_DIRECTIO; 1799f9b2a735SMimi Zohar break; 18000260643cSEric Richter case Opt_pcr: 18010260643cSEric Richter ima_log_string(ab, "pcr", args[0].from); 18020260643cSEric Richter 18030260643cSEric Richter result = kstrtoint(args[0].from, 10, &entry->pcr); 18040260643cSEric Richter if (result || INVALID_PCR(entry->pcr)) 18050260643cSEric Richter result = -EINVAL; 18060260643cSEric Richter else 18070260643cSEric Richter entry->flags |= IMA_PCR; 18080260643cSEric Richter 18090260643cSEric Richter break; 181019453ce0SMatthew Garrett case Opt_template: 181119453ce0SMatthew Garrett ima_log_string(ab, "template", args[0].from); 181219453ce0SMatthew Garrett if (entry->action != MEASURE) { 181319453ce0SMatthew Garrett result = -EINVAL; 181419453ce0SMatthew Garrett break; 181519453ce0SMatthew Garrett } 181619453ce0SMatthew Garrett template_desc = lookup_template_desc(args[0].from); 181719453ce0SMatthew Garrett if (!template_desc || entry->template) { 181819453ce0SMatthew Garrett result = -EINVAL; 181919453ce0SMatthew Garrett break; 182019453ce0SMatthew Garrett } 182119453ce0SMatthew Garrett 182219453ce0SMatthew Garrett /* 182319453ce0SMatthew Garrett * template_desc_init_fields() does nothing if 182419453ce0SMatthew Garrett * the template is already initialised, so 182519453ce0SMatthew Garrett * it's safe to do this unconditionally 182619453ce0SMatthew Garrett */ 182719453ce0SMatthew Garrett template_desc_init_fields(template_desc->fmt, 182819453ce0SMatthew Garrett &(template_desc->fields), 182919453ce0SMatthew Garrett &(template_desc->num_fields)); 183019453ce0SMatthew Garrett entry->template = template_desc; 183119453ce0SMatthew Garrett break; 18324af4662fSMimi Zohar case Opt_err: 18332f1506cdSEric Paris ima_log_string(ab, "UNKNOWN", p); 1834e9d393bfSEric Paris result = -EINVAL; 18354af4662fSMimi Zohar break; 18364af4662fSMimi Zohar } 18374af4662fSMimi Zohar } 183871218343STyler Hicks if (!result && !ima_validate_rule(entry)) 18394af4662fSMimi Zohar result = -EINVAL; 18406f0911a6SMimi Zohar else if (entry->action == APPRAISE) 18416f0911a6SMimi Zohar temp_ima_appraise |= ima_appraise_flag(entry->func); 18426f0911a6SMimi Zohar 18433878d505SThiago Jung Bauermann if (!result && entry->flags & IMA_MODSIG_ALLOWED) { 18443878d505SThiago Jung Bauermann template_desc = entry->template ? entry->template : 18453878d505SThiago Jung Bauermann ima_template_desc_current(); 18463878d505SThiago Jung Bauermann check_template_modsig(template_desc); 18473878d505SThiago Jung Bauermann } 18483878d505SThiago Jung Bauermann 184954f03916SMimi Zohar /* d-ngv2 template field recommended for unsigned fs-verity digests */ 185054f03916SMimi Zohar if (!result && entry->action == MEASURE && 185154f03916SMimi Zohar entry->flags & IMA_VERITY_REQUIRED) { 185254f03916SMimi Zohar template_desc = entry->template ? entry->template : 185354f03916SMimi Zohar ima_template_desc_current(); 185454f03916SMimi Zohar check_template_field(template_desc, "d-ngv2", 185554f03916SMimi Zohar "verity rules should include d-ngv2"); 185654f03916SMimi Zohar } 185754f03916SMimi Zohar 1858b0d5de4dSEric Paris audit_log_format(ab, "res=%d", !result); 18594af4662fSMimi Zohar audit_log_end(ab); 18604af4662fSMimi Zohar return result; 18614af4662fSMimi Zohar } 18624af4662fSMimi Zohar 18634af4662fSMimi Zohar /** 186407f6a794SMimi Zohar * ima_parse_add_rule - add a rule to ima_policy_rules 18654af4662fSMimi Zohar * @rule - ima measurement policy rule 18664af4662fSMimi Zohar * 186738d859f9SPetko Manolov * Avoid locking by allowing just one writer at a time in ima_write_policy() 18686ccd0456SEric Paris * Returns the length of the rule parsed, an error code on failure 18694af4662fSMimi Zohar */ 18706ccd0456SEric Paris ssize_t ima_parse_add_rule(char *rule) 18714af4662fSMimi Zohar { 187252a13284SMimi Zohar static const char op[] = "update_policy"; 18736ccd0456SEric Paris char *p; 187407f6a794SMimi Zohar struct ima_rule_entry *entry; 18756ccd0456SEric Paris ssize_t result, len; 18764af4662fSMimi Zohar int audit_info = 0; 18774af4662fSMimi Zohar 1878272a6e90SDmitry Kasatkin p = strsep(&rule, "\n"); 1879272a6e90SDmitry Kasatkin len = strlen(p) + 1; 18807178784fSDmitry Kasatkin p += strspn(p, " \t"); 1881272a6e90SDmitry Kasatkin 18827178784fSDmitry Kasatkin if (*p == '#' || *p == '\0') 1883272a6e90SDmitry Kasatkin return len; 1884272a6e90SDmitry Kasatkin 18854af4662fSMimi Zohar entry = kzalloc(sizeof(*entry), GFP_KERNEL); 18864af4662fSMimi Zohar if (!entry) { 18874af4662fSMimi Zohar integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 18884af4662fSMimi Zohar NULL, op, "-ENOMEM", -ENOMEM, audit_info); 18894af4662fSMimi Zohar return -ENOMEM; 18904af4662fSMimi Zohar } 18914af4662fSMimi Zohar 18924af4662fSMimi Zohar INIT_LIST_HEAD(&entry->list); 18934af4662fSMimi Zohar 18946ccd0456SEric Paris result = ima_parse_rule(p, entry); 18957233e3eeSEric Paris if (result) { 18962bdd737cSTyler Hicks ima_free_rule(entry); 1897523979adSMimi Zohar integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 18987e9001f6SRichard Guy Briggs NULL, op, "invalid-policy", result, 1899523979adSMimi Zohar audit_info); 19004af4662fSMimi Zohar return result; 19014af4662fSMimi Zohar } 19024af4662fSMimi Zohar 190338d859f9SPetko Manolov list_add_tail(&entry->list, &ima_temp_rules); 19047233e3eeSEric Paris 19057233e3eeSEric Paris return len; 19067233e3eeSEric Paris } 19077233e3eeSEric Paris 190838d859f9SPetko Manolov /** 190938d859f9SPetko Manolov * ima_delete_rules() called to cleanup invalid in-flight policy. 191038d859f9SPetko Manolov * We don't need locking as we operate on the temp list, which is 191138d859f9SPetko Manolov * different from the active one. There is also only one user of 191238d859f9SPetko Manolov * ima_delete_rules() at a time. 191338d859f9SPetko Manolov */ 191464c61d80SJames Morris void ima_delete_rules(void) 19154af4662fSMimi Zohar { 191607f6a794SMimi Zohar struct ima_rule_entry *entry, *tmp; 19174af4662fSMimi Zohar 19186ad6afa1SMimi Zohar temp_ima_appraise = 0; 191938d859f9SPetko Manolov list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) { 19204af4662fSMimi Zohar list_del(&entry->list); 1921465aee77STyler Hicks ima_free_rule(entry); 19224af4662fSMimi Zohar } 19234af4662fSMimi Zohar } 192480eae209SPetko Manolov 192534e980bbSLakshmi Ramasubramanian #define __ima_hook_stringify(func, str) (#func), 192639b07096SThiago Jung Bauermann 192739b07096SThiago Jung Bauermann const char *const func_tokens[] = { 192839b07096SThiago Jung Bauermann __ima_hooks(__ima_hook_stringify) 192939b07096SThiago Jung Bauermann }; 193039b07096SThiago Jung Bauermann 193180eae209SPetko Manolov #ifdef CONFIG_IMA_READ_POLICY 193280eae209SPetko Manolov enum { 193380eae209SPetko Manolov mask_exec = 0, mask_write, mask_read, mask_append 193480eae209SPetko Manolov }; 193580eae209SPetko Manolov 1936bb543e39SThiago Jung Bauermann static const char *const mask_tokens[] = { 19378cdc23a3SRoberto Sassu "^MAY_EXEC", 19388cdc23a3SRoberto Sassu "^MAY_WRITE", 19398cdc23a3SRoberto Sassu "^MAY_READ", 19408cdc23a3SRoberto Sassu "^MAY_APPEND" 194180eae209SPetko Manolov }; 194280eae209SPetko Manolov 194380eae209SPetko Manolov void *ima_policy_start(struct seq_file *m, loff_t *pos) 194480eae209SPetko Manolov { 194580eae209SPetko Manolov loff_t l = *pos; 194680eae209SPetko Manolov struct ima_rule_entry *entry; 1947eb0782bbSliqiong struct list_head *ima_rules_tmp; 194880eae209SPetko Manolov 194980eae209SPetko Manolov rcu_read_lock(); 1950eb0782bbSliqiong ima_rules_tmp = rcu_dereference(ima_rules); 1951eb0782bbSliqiong list_for_each_entry_rcu(entry, ima_rules_tmp, list) { 195280eae209SPetko Manolov if (!l--) { 195380eae209SPetko Manolov rcu_read_unlock(); 195480eae209SPetko Manolov return entry; 195580eae209SPetko Manolov } 195680eae209SPetko Manolov } 195780eae209SPetko Manolov rcu_read_unlock(); 195880eae209SPetko Manolov return NULL; 195980eae209SPetko Manolov } 196080eae209SPetko Manolov 196180eae209SPetko Manolov void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) 196280eae209SPetko Manolov { 196380eae209SPetko Manolov struct ima_rule_entry *entry = v; 196480eae209SPetko Manolov 196580eae209SPetko Manolov rcu_read_lock(); 196680eae209SPetko Manolov entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list); 196780eae209SPetko Manolov rcu_read_unlock(); 196880eae209SPetko Manolov (*pos)++; 196980eae209SPetko Manolov 1970eb0782bbSliqiong return (&entry->list == &ima_default_rules || 1971eb0782bbSliqiong &entry->list == &ima_policy_rules) ? NULL : entry; 197280eae209SPetko Manolov } 197380eae209SPetko Manolov 197480eae209SPetko Manolov void ima_policy_stop(struct seq_file *m, void *v) 197580eae209SPetko Manolov { 197680eae209SPetko Manolov } 197780eae209SPetko Manolov 19781a9430dbSMimi Zohar #define pt(token) policy_tokens[token].pattern 197980eae209SPetko Manolov #define mt(token) mask_tokens[token] 198080eae209SPetko Manolov 1981b5269ab3SMimi Zohar /* 1982b5269ab3SMimi Zohar * policy_func_show - display the ima_hooks policy rule 1983b5269ab3SMimi Zohar */ 1984b5269ab3SMimi Zohar static void policy_func_show(struct seq_file *m, enum ima_hooks func) 1985b5269ab3SMimi Zohar { 19862663218bSThiago Jung Bauermann if (func > 0 && func < MAX_CHECK) 19872663218bSThiago Jung Bauermann seq_printf(m, "func=%s ", func_tokens[func]); 19882663218bSThiago Jung Bauermann else 19892663218bSThiago Jung Bauermann seq_printf(m, "func=%d ", func); 1990b5269ab3SMimi Zohar } 1991b5269ab3SMimi Zohar 1992176377d9STyler Hicks static void ima_show_rule_opt_list(struct seq_file *m, 1993176377d9STyler Hicks const struct ima_rule_opt_list *opt_list) 1994176377d9STyler Hicks { 1995176377d9STyler Hicks size_t i; 1996176377d9STyler Hicks 1997176377d9STyler Hicks for (i = 0; i < opt_list->count; i++) 1998176377d9STyler Hicks seq_printf(m, "%s%s", i ? "|" : "", opt_list->items[i]); 1999176377d9STyler Hicks } 2000176377d9STyler Hicks 2001583a80aeSTHOBY Simon static void ima_policy_show_appraise_algos(struct seq_file *m, 2002583a80aeSTHOBY Simon unsigned int allowed_hashes) 2003583a80aeSTHOBY Simon { 2004583a80aeSTHOBY Simon int idx, list_size = 0; 2005583a80aeSTHOBY Simon 2006583a80aeSTHOBY Simon for (idx = 0; idx < HASH_ALGO__LAST; idx++) { 2007583a80aeSTHOBY Simon if (!(allowed_hashes & (1U << idx))) 2008583a80aeSTHOBY Simon continue; 2009583a80aeSTHOBY Simon 2010583a80aeSTHOBY Simon /* only add commas if the list contains multiple entries */ 2011583a80aeSTHOBY Simon if (list_size++) 2012583a80aeSTHOBY Simon seq_puts(m, ","); 2013583a80aeSTHOBY Simon 2014583a80aeSTHOBY Simon seq_puts(m, hash_algo_name[idx]); 2015583a80aeSTHOBY Simon } 2016583a80aeSTHOBY Simon } 2017583a80aeSTHOBY Simon 201880eae209SPetko Manolov int ima_policy_show(struct seq_file *m, void *v) 201980eae209SPetko Manolov { 202080eae209SPetko Manolov struct ima_rule_entry *entry = v; 2021b8b57278SAndy Shevchenko int i; 202280eae209SPetko Manolov char tbuf[64] = {0,}; 20238cdc23a3SRoberto Sassu int offset = 0; 202480eae209SPetko Manolov 202580eae209SPetko Manolov rcu_read_lock(); 202680eae209SPetko Manolov 202789677197SStefan Berger /* Do not print rules with inactive LSM labels */ 202889677197SStefan Berger for (i = 0; i < MAX_LSM_RULES; i++) { 202989677197SStefan Berger if (entry->lsm[i].args_p && !entry->lsm[i].rule) { 203089677197SStefan Berger rcu_read_unlock(); 203189677197SStefan Berger return 0; 203289677197SStefan Berger } 203389677197SStefan Berger } 203489677197SStefan Berger 203580eae209SPetko Manolov if (entry->action & MEASURE) 203680eae209SPetko Manolov seq_puts(m, pt(Opt_measure)); 203780eae209SPetko Manolov if (entry->action & DONT_MEASURE) 203880eae209SPetko Manolov seq_puts(m, pt(Opt_dont_measure)); 203980eae209SPetko Manolov if (entry->action & APPRAISE) 204080eae209SPetko Manolov seq_puts(m, pt(Opt_appraise)); 204180eae209SPetko Manolov if (entry->action & DONT_APPRAISE) 204280eae209SPetko Manolov seq_puts(m, pt(Opt_dont_appraise)); 204380eae209SPetko Manolov if (entry->action & AUDIT) 204480eae209SPetko Manolov seq_puts(m, pt(Opt_audit)); 2045da1b0029SMimi Zohar if (entry->action & HASH) 2046da1b0029SMimi Zohar seq_puts(m, pt(Opt_hash)); 2047da1b0029SMimi Zohar if (entry->action & DONT_HASH) 2048da1b0029SMimi Zohar seq_puts(m, pt(Opt_dont_hash)); 204980eae209SPetko Manolov 205080eae209SPetko Manolov seq_puts(m, " "); 205180eae209SPetko Manolov 2052b5269ab3SMimi Zohar if (entry->flags & IMA_FUNC) 2053b5269ab3SMimi Zohar policy_func_show(m, entry->func); 205480eae209SPetko Manolov 20558cdc23a3SRoberto Sassu if ((entry->flags & IMA_MASK) || (entry->flags & IMA_INMASK)) { 20568cdc23a3SRoberto Sassu if (entry->flags & IMA_MASK) 20578cdc23a3SRoberto Sassu offset = 1; 205880eae209SPetko Manolov if (entry->mask & MAY_EXEC) 20598cdc23a3SRoberto Sassu seq_printf(m, pt(Opt_mask), mt(mask_exec) + offset); 206080eae209SPetko Manolov if (entry->mask & MAY_WRITE) 20618cdc23a3SRoberto Sassu seq_printf(m, pt(Opt_mask), mt(mask_write) + offset); 206280eae209SPetko Manolov if (entry->mask & MAY_READ) 20638cdc23a3SRoberto Sassu seq_printf(m, pt(Opt_mask), mt(mask_read) + offset); 206480eae209SPetko Manolov if (entry->mask & MAY_APPEND) 20658cdc23a3SRoberto Sassu seq_printf(m, pt(Opt_mask), mt(mask_append) + offset); 206680eae209SPetko Manolov seq_puts(m, " "); 206780eae209SPetko Manolov } 206880eae209SPetko Manolov 206980eae209SPetko Manolov if (entry->flags & IMA_FSMAGIC) { 207080eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "0x%lx", entry->fsmagic); 207180eae209SPetko Manolov seq_printf(m, pt(Opt_fsmagic), tbuf); 207280eae209SPetko Manolov seq_puts(m, " "); 207380eae209SPetko Manolov } 207480eae209SPetko Manolov 2075f1b08bbcSMimi Zohar if (entry->flags & IMA_FSNAME) { 2076f1b08bbcSMimi Zohar snprintf(tbuf, sizeof(tbuf), "%s", entry->fsname); 2077f1b08bbcSMimi Zohar seq_printf(m, pt(Opt_fsname), tbuf); 2078f1b08bbcSMimi Zohar seq_puts(m, " "); 2079f1b08bbcSMimi Zohar } 2080f1b08bbcSMimi Zohar 20812b60c0ecSLakshmi Ramasubramanian if (entry->flags & IMA_KEYRINGS) { 2082176377d9STyler Hicks seq_puts(m, "keyrings="); 2083176377d9STyler Hicks ima_show_rule_opt_list(m, entry->keyrings); 20842b60c0ecSLakshmi Ramasubramanian seq_puts(m, " "); 20852b60c0ecSLakshmi Ramasubramanian } 20862b60c0ecSLakshmi Ramasubramanian 208747d76a48STushar Sugandhi if (entry->flags & IMA_LABEL) { 208847d76a48STushar Sugandhi seq_puts(m, "label="); 208947d76a48STushar Sugandhi ima_show_rule_opt_list(m, entry->label); 209047d76a48STushar Sugandhi seq_puts(m, " "); 209147d76a48STushar Sugandhi } 209247d76a48STushar Sugandhi 20930260643cSEric Richter if (entry->flags & IMA_PCR) { 20940260643cSEric Richter snprintf(tbuf, sizeof(tbuf), "%d", entry->pcr); 20950260643cSEric Richter seq_printf(m, pt(Opt_pcr), tbuf); 20960260643cSEric Richter seq_puts(m, " "); 20970260643cSEric Richter } 20980260643cSEric Richter 209980eae209SPetko Manolov if (entry->flags & IMA_FSUUID) { 2100787d8c53SChristoph Hellwig seq_printf(m, "fsuuid=%pU", &entry->fsuuid); 210180eae209SPetko Manolov seq_puts(m, " "); 210280eae209SPetko Manolov } 210380eae209SPetko Manolov 210480eae209SPetko Manolov if (entry->flags & IMA_UID) { 210580eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); 21063dd0c8d0SMikhail Kurinnoi if (entry->uid_op == &uid_gt) 21073dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_uid_gt), tbuf); 21083dd0c8d0SMikhail Kurinnoi else if (entry->uid_op == &uid_lt) 21093dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_uid_lt), tbuf); 21103dd0c8d0SMikhail Kurinnoi else 21113dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_uid_eq), tbuf); 211280eae209SPetko Manolov seq_puts(m, " "); 211380eae209SPetko Manolov } 211480eae209SPetko Manolov 211580eae209SPetko Manolov if (entry->flags & IMA_EUID) { 211680eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); 21173dd0c8d0SMikhail Kurinnoi if (entry->uid_op == &uid_gt) 21183dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_euid_gt), tbuf); 21193dd0c8d0SMikhail Kurinnoi else if (entry->uid_op == &uid_lt) 21203dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_euid_lt), tbuf); 21213dd0c8d0SMikhail Kurinnoi else 21223dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_euid_eq), tbuf); 212380eae209SPetko Manolov seq_puts(m, " "); 212480eae209SPetko Manolov } 212580eae209SPetko Manolov 212640224c41SCurtis Veit if (entry->flags & IMA_GID) { 212740224c41SCurtis Veit snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid)); 212840224c41SCurtis Veit if (entry->gid_op == &gid_gt) 212940224c41SCurtis Veit seq_printf(m, pt(Opt_gid_gt), tbuf); 213040224c41SCurtis Veit else if (entry->gid_op == &gid_lt) 213140224c41SCurtis Veit seq_printf(m, pt(Opt_gid_lt), tbuf); 213240224c41SCurtis Veit else 213340224c41SCurtis Veit seq_printf(m, pt(Opt_gid_eq), tbuf); 213440224c41SCurtis Veit seq_puts(m, " "); 213540224c41SCurtis Veit } 213640224c41SCurtis Veit 213740224c41SCurtis Veit if (entry->flags & IMA_EGID) { 213840224c41SCurtis Veit snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid)); 213940224c41SCurtis Veit if (entry->gid_op == &gid_gt) 214040224c41SCurtis Veit seq_printf(m, pt(Opt_egid_gt), tbuf); 214140224c41SCurtis Veit else if (entry->gid_op == &gid_lt) 214240224c41SCurtis Veit seq_printf(m, pt(Opt_egid_lt), tbuf); 214340224c41SCurtis Veit else 214440224c41SCurtis Veit seq_printf(m, pt(Opt_egid_eq), tbuf); 214540224c41SCurtis Veit seq_puts(m, " "); 214640224c41SCurtis Veit } 214740224c41SCurtis Veit 214880eae209SPetko Manolov if (entry->flags & IMA_FOWNER) { 214980eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); 21503dd0c8d0SMikhail Kurinnoi if (entry->fowner_op == &uid_gt) 21513dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_fowner_gt), tbuf); 21523dd0c8d0SMikhail Kurinnoi else if (entry->fowner_op == &uid_lt) 21533dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_fowner_lt), tbuf); 21543dd0c8d0SMikhail Kurinnoi else 21553dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_fowner_eq), tbuf); 215680eae209SPetko Manolov seq_puts(m, " "); 215780eae209SPetko Manolov } 215880eae209SPetko Manolov 215940224c41SCurtis Veit if (entry->flags & IMA_FGROUP) { 216040224c41SCurtis Veit snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup)); 216140224c41SCurtis Veit if (entry->fgroup_op == &gid_gt) 216240224c41SCurtis Veit seq_printf(m, pt(Opt_fgroup_gt), tbuf); 216340224c41SCurtis Veit else if (entry->fgroup_op == &gid_lt) 216440224c41SCurtis Veit seq_printf(m, pt(Opt_fgroup_lt), tbuf); 216540224c41SCurtis Veit else 216640224c41SCurtis Veit seq_printf(m, pt(Opt_fgroup_eq), tbuf); 216740224c41SCurtis Veit seq_puts(m, " "); 216840224c41SCurtis Veit } 216940224c41SCurtis Veit 2170583a80aeSTHOBY Simon if (entry->flags & IMA_VALIDATE_ALGOS) { 2171583a80aeSTHOBY Simon seq_puts(m, "appraise_algos="); 2172583a80aeSTHOBY Simon ima_policy_show_appraise_algos(m, entry->allowed_algos); 2173583a80aeSTHOBY Simon seq_puts(m, " "); 2174583a80aeSTHOBY Simon } 2175583a80aeSTHOBY Simon 217680eae209SPetko Manolov for (i = 0; i < MAX_LSM_RULES; i++) { 217780eae209SPetko Manolov if (entry->lsm[i].rule) { 217880eae209SPetko Manolov switch (i) { 217980eae209SPetko Manolov case LSM_OBJ_USER: 218080eae209SPetko Manolov seq_printf(m, pt(Opt_obj_user), 2181aa0c0227STyler Hicks entry->lsm[i].args_p); 218280eae209SPetko Manolov break; 218380eae209SPetko Manolov case LSM_OBJ_ROLE: 218480eae209SPetko Manolov seq_printf(m, pt(Opt_obj_role), 2185aa0c0227STyler Hicks entry->lsm[i].args_p); 218680eae209SPetko Manolov break; 218780eae209SPetko Manolov case LSM_OBJ_TYPE: 218880eae209SPetko Manolov seq_printf(m, pt(Opt_obj_type), 2189aa0c0227STyler Hicks entry->lsm[i].args_p); 219080eae209SPetko Manolov break; 219180eae209SPetko Manolov case LSM_SUBJ_USER: 219280eae209SPetko Manolov seq_printf(m, pt(Opt_subj_user), 2193aa0c0227STyler Hicks entry->lsm[i].args_p); 219480eae209SPetko Manolov break; 219580eae209SPetko Manolov case LSM_SUBJ_ROLE: 219680eae209SPetko Manolov seq_printf(m, pt(Opt_subj_role), 2197aa0c0227STyler Hicks entry->lsm[i].args_p); 219880eae209SPetko Manolov break; 219980eae209SPetko Manolov case LSM_SUBJ_TYPE: 220080eae209SPetko Manolov seq_printf(m, pt(Opt_subj_type), 2201aa0c0227STyler Hicks entry->lsm[i].args_p); 220280eae209SPetko Manolov break; 220380eae209SPetko Manolov } 22045350ceb0SClay Chang seq_puts(m, " "); 220580eae209SPetko Manolov } 220680eae209SPetko Manolov } 220719453ce0SMatthew Garrett if (entry->template) 220819453ce0SMatthew Garrett seq_printf(m, "template=%s ", entry->template->name); 22099044d627SThiago Jung Bauermann if (entry->flags & IMA_DIGSIG_REQUIRED) { 2210398c42e2SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 2211398c42e2SMimi Zohar seq_puts(m, "appraise_type=sigv3 "); 2212398c42e2SMimi Zohar else if (entry->flags & IMA_MODSIG_ALLOWED) 22139044d627SThiago Jung Bauermann seq_puts(m, "appraise_type=imasig|modsig "); 22149044d627SThiago Jung Bauermann else 221580eae209SPetko Manolov seq_puts(m, "appraise_type=imasig "); 22169044d627SThiago Jung Bauermann } 221754f03916SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 221854f03916SMimi Zohar seq_puts(m, "digest_type=verity "); 2219273df864SNayna Jain if (entry->flags & IMA_CHECK_BLACKLIST) 2220273df864SNayna Jain seq_puts(m, "appraise_flag=check_blacklist "); 222180eae209SPetko Manolov if (entry->flags & IMA_PERMIT_DIRECTIO) 222280eae209SPetko Manolov seq_puts(m, "permit_directio "); 222380eae209SPetko Manolov rcu_read_unlock(); 222480eae209SPetko Manolov seq_puts(m, "\n"); 222580eae209SPetko Manolov return 0; 222680eae209SPetko Manolov } 222780eae209SPetko Manolov #endif /* CONFIG_IMA_READ_POLICY */ 222829d3c1c8SMatthew Garrett 222929d3c1c8SMatthew Garrett #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) 223029d3c1c8SMatthew Garrett /* 223129d3c1c8SMatthew Garrett * ima_appraise_signature: whether IMA will appraise a given function using 223229d3c1c8SMatthew Garrett * an IMA digital signature. This is restricted to cases where the kernel 223329d3c1c8SMatthew Garrett * has a set of built-in trusted keys in order to avoid an attacker simply 223429d3c1c8SMatthew Garrett * loading additional keys. 223529d3c1c8SMatthew Garrett */ 223629d3c1c8SMatthew Garrett bool ima_appraise_signature(enum kernel_read_file_id id) 223729d3c1c8SMatthew Garrett { 223829d3c1c8SMatthew Garrett struct ima_rule_entry *entry; 223929d3c1c8SMatthew Garrett bool found = false; 224029d3c1c8SMatthew Garrett enum ima_hooks func; 2241eb0782bbSliqiong struct list_head *ima_rules_tmp; 224229d3c1c8SMatthew Garrett 224329d3c1c8SMatthew Garrett if (id >= READING_MAX_ID) 224429d3c1c8SMatthew Garrett return false; 224529d3c1c8SMatthew Garrett 2246543ce63bSEric Snowberg if (id == READING_KEXEC_IMAGE && !(ima_appraise & IMA_APPRAISE_ENFORCE) 2247543ce63bSEric Snowberg && security_locked_down(LOCKDOWN_KEXEC)) 2248543ce63bSEric Snowberg return false; 2249543ce63bSEric Snowberg 225029d3c1c8SMatthew Garrett func = read_idmap[id] ?: FILE_CHECK; 225129d3c1c8SMatthew Garrett 225229d3c1c8SMatthew Garrett rcu_read_lock(); 2253eb0782bbSliqiong ima_rules_tmp = rcu_dereference(ima_rules); 2254eb0782bbSliqiong list_for_each_entry_rcu(entry, ima_rules_tmp, list) { 225529d3c1c8SMatthew Garrett if (entry->action != APPRAISE) 225629d3c1c8SMatthew Garrett continue; 225729d3c1c8SMatthew Garrett 225829d3c1c8SMatthew Garrett /* 225929d3c1c8SMatthew Garrett * A generic entry will match, but otherwise require that it 226029d3c1c8SMatthew Garrett * match the func we're looking for 226129d3c1c8SMatthew Garrett */ 226229d3c1c8SMatthew Garrett if (entry->func && entry->func != func) 226329d3c1c8SMatthew Garrett continue; 226429d3c1c8SMatthew Garrett 226529d3c1c8SMatthew Garrett /* 226629d3c1c8SMatthew Garrett * We require this to be a digital signature, not a raw IMA 226729d3c1c8SMatthew Garrett * hash. 226829d3c1c8SMatthew Garrett */ 226929d3c1c8SMatthew Garrett if (entry->flags & IMA_DIGSIG_REQUIRED) 227029d3c1c8SMatthew Garrett found = true; 227129d3c1c8SMatthew Garrett 227229d3c1c8SMatthew Garrett /* 227329d3c1c8SMatthew Garrett * We've found a rule that matches, so break now even if it 227429d3c1c8SMatthew Garrett * didn't require a digital signature - a later rule that does 227529d3c1c8SMatthew Garrett * won't override it, so would be a false positive. 227629d3c1c8SMatthew Garrett */ 227729d3c1c8SMatthew Garrett break; 227829d3c1c8SMatthew Garrett } 227929d3c1c8SMatthew Garrett 228029d3c1c8SMatthew Garrett rcu_read_unlock(); 228129d3c1c8SMatthew Garrett return found; 228229d3c1c8SMatthew Garrett } 228329d3c1c8SMatthew Garrett #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */ 2284