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) || \ 524de2f084SRoberto Sassu (a) >= (sizeof_field(struct ima_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; 71a4b35d4dSKees Cook char *items[] __counted_by(count); 72176377d9STyler Hicks }; 73176377d9STyler Hicks 742c05bf3aSChristian Brauner /* 752c05bf3aSChristian Brauner * These comparators are needed nowhere outside of ima so just define them here. 762c05bf3aSChristian Brauner * This pattern should hopefully never be needed outside of ima. 772c05bf3aSChristian Brauner */ 782c05bf3aSChristian Brauner static inline bool vfsuid_gt_kuid(vfsuid_t vfsuid, kuid_t kuid) 792c05bf3aSChristian Brauner { 802c05bf3aSChristian Brauner return __vfsuid_val(vfsuid) > __kuid_val(kuid); 812c05bf3aSChristian Brauner } 822c05bf3aSChristian Brauner 832c05bf3aSChristian Brauner static inline bool vfsgid_gt_kgid(vfsgid_t vfsgid, kgid_t kgid) 842c05bf3aSChristian Brauner { 852c05bf3aSChristian Brauner return __vfsgid_val(vfsgid) > __kgid_val(kgid); 862c05bf3aSChristian Brauner } 872c05bf3aSChristian Brauner 882c05bf3aSChristian Brauner static inline bool vfsuid_lt_kuid(vfsuid_t vfsuid, kuid_t kuid) 892c05bf3aSChristian Brauner { 902c05bf3aSChristian Brauner return __vfsuid_val(vfsuid) < __kuid_val(kuid); 912c05bf3aSChristian Brauner } 922c05bf3aSChristian Brauner 932c05bf3aSChristian Brauner static inline bool vfsgid_lt_kgid(vfsgid_t vfsgid, kgid_t kgid) 942c05bf3aSChristian Brauner { 952c05bf3aSChristian Brauner return __vfsgid_val(vfsgid) < __kgid_val(kgid); 962c05bf3aSChristian Brauner } 972c05bf3aSChristian Brauner 9807f6a794SMimi Zohar struct ima_rule_entry { 993323eec9SMimi Zohar struct list_head list; 1002fe5d6deSMimi Zohar int action; 1013323eec9SMimi Zohar unsigned int flags; 1023323eec9SMimi Zohar enum ima_hooks func; 1033323eec9SMimi Zohar int mask; 1043323eec9SMimi Zohar unsigned long fsmagic; 105787d8c53SChristoph Hellwig uuid_t fsuuid; 1068b94eea4SEric W. Biederman kuid_t uid; 10740224c41SCurtis Veit kgid_t gid; 10888265322SLinus Torvalds kuid_t fowner; 10940224c41SCurtis Veit kgid_t fgroup; 11030d8764aSAlex Henrie bool (*uid_op)(kuid_t cred_uid, kuid_t rule_uid); /* Handlers for operators */ 11140224c41SCurtis Veit bool (*gid_op)(kgid_t cred_gid, kgid_t rule_gid); 1128e27a7aeSChristian Brauner bool (*fowner_op)(vfsuid_t vfsuid, kuid_t rule_uid); /* vfsuid_eq_kuid(), vfsuid_gt_kuid(), vfsuid_lt_kuid() */ 1138e27a7aeSChristian Brauner bool (*fgroup_op)(vfsgid_t vfsgid, kgid_t rule_gid); /* vfsgid_eq_kgid(), vfsgid_gt_kgid(), vfsgid_lt_kgid() */ 1140260643cSEric Richter int pcr; 1151624dc00STHOBY Simon unsigned int allowed_algos; /* bitfield of allowed hash algorithms */ 1164af4662fSMimi Zohar struct { 1174af4662fSMimi Zohar void *rule; /* LSM file metadata specific */ 118aa0c0227STyler Hicks char *args_p; /* audit value */ 1194af4662fSMimi Zohar int type; /* audit type */ 1204af4662fSMimi Zohar } lsm[MAX_LSM_RULES]; 121f1b08bbcSMimi Zohar char *fsname; 122176377d9STyler Hicks struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */ 12347d76a48STushar Sugandhi struct ima_rule_opt_list *label; /* Measure data grouped under this label */ 12419453ce0SMatthew Garrett struct ima_template_desc *template; 1253323eec9SMimi Zohar }; 1263323eec9SMimi Zohar 1275789ba3bSEric Paris /* 1281624dc00STHOBY Simon * sanity check in case the kernels gains more hash algorithms that can 1291624dc00STHOBY Simon * fit in an unsigned int 1301624dc00STHOBY Simon */ 1311624dc00STHOBY Simon static_assert( 1321624dc00STHOBY Simon 8 * sizeof(unsigned int) >= HASH_ALGO__LAST, 1331624dc00STHOBY Simon "The bitfield allowed_algos in ima_rule_entry is too small to contain all the supported hash algorithms, consider using a bigger type"); 1341624dc00STHOBY Simon 1351624dc00STHOBY Simon /* 1365789ba3bSEric Paris * Without LSM specific knowledge, the default policy can only be 13740224c41SCurtis Veit * written in terms of .action, .func, .mask, .fsmagic, .uid, .gid, 13840224c41SCurtis Veit * .fowner, and .fgroup 1394af4662fSMimi Zohar */ 1405789ba3bSEric Paris 1415789ba3bSEric Paris /* 1425789ba3bSEric Paris * The minimum rule set to allow for full TCB coverage. Measures all files 1435789ba3bSEric Paris * opened or mmap for exec and everything read by root. Dangerous because 1445789ba3bSEric Paris * normal users can easily run the machine out of memory simply building 1455789ba3bSEric Paris * and running executables. 1465789ba3bSEric Paris */ 147bad4417bSJames Morris static struct ima_rule_entry dont_measure_rules[] __ro_after_init = { 14875834fc3SEric Paris {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 1493323eec9SMimi Zohar {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, 1503323eec9SMimi Zohar {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, 1513323eec9SMimi Zohar {.action = DONT_MEASURE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, 1528445d64dSDmitry Kasatkin {.action = DONT_MEASURE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 1538445d64dSDmitry Kasatkin {.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, 15475834fc3SEric Paris {.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, 15575834fc3SEric Paris {.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, 1561c070b18SMartin Townsend {.action = DONT_MEASURE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, 1576438de9fSRoberto Sassu {.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC, 1586438de9fSRoberto Sassu .flags = IMA_FSMAGIC}, 15982e3bb4dSLaura Abbott {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC, 16082e3bb4dSLaura Abbott .flags = IMA_FSMAGIC}, 161060190fbSMimi Zohar {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, 162060190fbSMimi Zohar {.action = DONT_MEASURE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC} 16324fd03c8SMimi Zohar }; 16424fd03c8SMimi Zohar 165bad4417bSJames Morris static struct ima_rule_entry original_measurement_rules[] __ro_after_init = { 16616cac49fSMimi Zohar {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, 1673323eec9SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 1683323eec9SMimi Zohar {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, 1693323eec9SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 17024fd03c8SMimi Zohar {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 1713dd0c8d0SMikhail Kurinnoi .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, 1723dd0c8d0SMikhail Kurinnoi .flags = IMA_FUNC | IMA_MASK | IMA_UID}, 17324fd03c8SMimi Zohar {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, 17424fd03c8SMimi Zohar {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, 17524fd03c8SMimi Zohar }; 17624fd03c8SMimi Zohar 177bad4417bSJames Morris static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { 17824fd03c8SMimi Zohar {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, 17924fd03c8SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 18024fd03c8SMimi Zohar {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, 18124fd03c8SMimi Zohar .flags = IMA_FUNC | IMA_MASK}, 18224fd03c8SMimi Zohar {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 1833dd0c8d0SMikhail Kurinnoi .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, 1843dd0c8d0SMikhail Kurinnoi .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, 18524fd03c8SMimi Zohar {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, 1863dd0c8d0SMikhail Kurinnoi .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, 1873dd0c8d0SMikhail Kurinnoi .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, 188fdf90729SMimi Zohar {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, 1895a9196d7SMimi Zohar {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, 19019f8a847SMimi Zohar {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, 1913323eec9SMimi Zohar }; 1923323eec9SMimi Zohar 193bad4417bSJames Morris static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { 19407f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 19507f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, 19607f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, 19707f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, 19807f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = RAMFS_MAGIC, .flags = IMA_FSMAGIC}, 19907f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 20007f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, 20107f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, 20207f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, 2031c070b18SMartin Townsend {.action = DONT_APPRAISE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, 204cd025f7fSMimi Zohar {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, 205060190fbSMimi Zohar {.action = DONT_APPRAISE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC}, 20607f6a794SMimi Zohar {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 20782e3bb4dSLaura Abbott {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC}, 20895ee08faSMimi Zohar #ifdef CONFIG_IMA_WRITE_POLICY 20995ee08faSMimi Zohar {.action = APPRAISE, .func = POLICY_CHECK, 21095ee08faSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 21195ee08faSMimi Zohar #endif 212c57782c1SDmitry Kasatkin #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT 2138e27a7aeSChristian Brauner {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid, 2143dd0c8d0SMikhail Kurinnoi .flags = IMA_FOWNER}, 215c57782c1SDmitry Kasatkin #else 216c57782c1SDmitry Kasatkin /* force signature */ 2178e27a7aeSChristian Brauner {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid, 218c57782c1SDmitry Kasatkin .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, 219c57782c1SDmitry Kasatkin #endif 22007f6a794SMimi Zohar }; 2213323eec9SMimi Zohar 222ef96837bSMimi Zohar static struct ima_rule_entry build_appraise_rules[] __ro_after_init = { 223ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_MODULE_SIGS 224ef96837bSMimi Zohar {.action = APPRAISE, .func = MODULE_CHECK, 225ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 226ef96837bSMimi Zohar #endif 227ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_FIRMWARE_SIGS 228ef96837bSMimi Zohar {.action = APPRAISE, .func = FIRMWARE_CHECK, 229ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 230ef96837bSMimi Zohar #endif 231ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_KEXEC_SIGS 232ef96837bSMimi Zohar {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK, 233ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 234ef96837bSMimi Zohar #endif 235ef96837bSMimi Zohar #ifdef CONFIG_IMA_APPRAISE_REQUIRE_POLICY_SIGS 236ef96837bSMimi Zohar {.action = APPRAISE, .func = POLICY_CHECK, 237ef96837bSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 238ef96837bSMimi Zohar #endif 239ef96837bSMimi Zohar }; 240ef96837bSMimi Zohar 241503ceaefSMimi Zohar static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { 242503ceaefSMimi Zohar {.action = APPRAISE, .func = MODULE_CHECK, 243503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 244503ceaefSMimi Zohar {.action = APPRAISE, .func = FIRMWARE_CHECK, 245503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 246503ceaefSMimi Zohar {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK, 247503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 248503ceaefSMimi Zohar {.action = APPRAISE, .func = POLICY_CHECK, 249503ceaefSMimi Zohar .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, 250503ceaefSMimi Zohar }; 251503ceaefSMimi Zohar 25203cee168SLakshmi Ramasubramanian static struct ima_rule_entry critical_data_rules[] __ro_after_init = { 25303cee168SLakshmi Ramasubramanian {.action = MEASURE, .func = CRITICAL_DATA, .flags = IMA_FUNC}, 25403cee168SLakshmi Ramasubramanian }; 25503cee168SLakshmi Ramasubramanian 25661917062SNayna Jain /* An array of architecture specific rules */ 25768f25290SYueHaibing static struct ima_rule_entry *arch_policy_entry __ro_after_init; 25861917062SNayna Jain 25907f6a794SMimi Zohar static LIST_HEAD(ima_default_rules); 26007f6a794SMimi Zohar static LIST_HEAD(ima_policy_rules); 26138d859f9SPetko Manolov static LIST_HEAD(ima_temp_rules); 262eb0782bbSliqiong static struct list_head __rcu *ima_rules = (struct list_head __rcu *)(&ima_default_rules); 26307f6a794SMimi Zohar 26424fd03c8SMimi Zohar static int ima_policy __initdata; 26538d859f9SPetko Manolov 26607f6a794SMimi Zohar static int __init default_measure_policy_setup(char *str) 2675789ba3bSEric Paris { 26824fd03c8SMimi Zohar if (ima_policy) 26924fd03c8SMimi Zohar return 1; 27024fd03c8SMimi Zohar 27124fd03c8SMimi Zohar ima_policy = ORIGINAL_TCB; 2725789ba3bSEric Paris return 1; 2735789ba3bSEric Paris } 27407f6a794SMimi Zohar __setup("ima_tcb", default_measure_policy_setup); 27507f6a794SMimi Zohar 27633ce9549SMimi Zohar static bool ima_use_appraise_tcb __initdata; 277503ceaefSMimi Zohar static bool ima_use_secure_boot __initdata; 27803cee168SLakshmi Ramasubramanian static bool ima_use_critical_data __initdata; 2799e67028eSMimi Zohar static bool ima_fail_unverifiable_sigs __ro_after_init; 28024fd03c8SMimi Zohar static int __init policy_setup(char *str) 28124fd03c8SMimi Zohar { 28233ce9549SMimi Zohar char *p; 28324fd03c8SMimi Zohar 28433ce9549SMimi Zohar while ((p = strsep(&str, " |\n")) != NULL) { 28533ce9549SMimi Zohar if (*p == ' ') 28633ce9549SMimi Zohar continue; 28733ce9549SMimi Zohar if ((strcmp(p, "tcb") == 0) && !ima_policy) 28824fd03c8SMimi Zohar ima_policy = DEFAULT_TCB; 28933ce9549SMimi Zohar else if (strcmp(p, "appraise_tcb") == 0) 29039adb925SThomas Meyer ima_use_appraise_tcb = true; 291503ceaefSMimi Zohar else if (strcmp(p, "secure_boot") == 0) 29239adb925SThomas Meyer ima_use_secure_boot = true; 29303cee168SLakshmi Ramasubramanian else if (strcmp(p, "critical_data") == 0) 29403cee168SLakshmi Ramasubramanian ima_use_critical_data = true; 2959e67028eSMimi Zohar else if (strcmp(p, "fail_securely") == 0) 2969e67028eSMimi Zohar ima_fail_unverifiable_sigs = true; 2977fe2bb7eSBruno Meneguele else 2987fe2bb7eSBruno Meneguele pr_err("policy \"%s\" not found", p); 29933ce9549SMimi Zohar } 30024fd03c8SMimi Zohar 30124fd03c8SMimi Zohar return 1; 30224fd03c8SMimi Zohar } 30324fd03c8SMimi Zohar __setup("ima_policy=", policy_setup); 30424fd03c8SMimi Zohar 30507f6a794SMimi Zohar static int __init default_appraise_policy_setup(char *str) 30607f6a794SMimi Zohar { 30739adb925SThomas Meyer ima_use_appraise_tcb = true; 30807f6a794SMimi Zohar return 1; 30907f6a794SMimi Zohar } 31007f6a794SMimi Zohar __setup("ima_appraise_tcb", default_appraise_policy_setup); 3115789ba3bSEric Paris 312176377d9STyler Hicks static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src) 313176377d9STyler Hicks { 314176377d9STyler Hicks struct ima_rule_opt_list *opt_list; 315176377d9STyler Hicks size_t count = 0; 316176377d9STyler Hicks char *src_copy; 317176377d9STyler Hicks char *cur, *next; 318176377d9STyler Hicks size_t i; 319176377d9STyler Hicks 320176377d9STyler Hicks src_copy = match_strdup(src); 321176377d9STyler Hicks if (!src_copy) 322176377d9STyler Hicks return ERR_PTR(-ENOMEM); 323176377d9STyler Hicks 324176377d9STyler Hicks next = src_copy; 325176377d9STyler Hicks while ((cur = strsep(&next, "|"))) { 326176377d9STyler Hicks /* Don't accept an empty list item */ 327176377d9STyler Hicks if (!(*cur)) { 328176377d9STyler Hicks kfree(src_copy); 329176377d9STyler Hicks return ERR_PTR(-EINVAL); 330176377d9STyler Hicks } 331176377d9STyler Hicks count++; 332176377d9STyler Hicks } 333176377d9STyler Hicks 334176377d9STyler Hicks /* Don't accept an empty list */ 335176377d9STyler Hicks if (!count) { 336176377d9STyler Hicks kfree(src_copy); 337176377d9STyler Hicks return ERR_PTR(-EINVAL); 338176377d9STyler Hicks } 339176377d9STyler Hicks 340176377d9STyler Hicks opt_list = kzalloc(struct_size(opt_list, items, count), GFP_KERNEL); 341176377d9STyler Hicks if (!opt_list) { 342176377d9STyler Hicks kfree(src_copy); 343176377d9STyler Hicks return ERR_PTR(-ENOMEM); 344176377d9STyler Hicks } 345a4b35d4dSKees Cook opt_list->count = count; 346176377d9STyler Hicks 347176377d9STyler Hicks /* 348176377d9STyler Hicks * strsep() has already replaced all instances of '|' with '\0', 349176377d9STyler Hicks * leaving a byte sequence of NUL-terminated strings. Reference each 350176377d9STyler Hicks * string with the array of items. 351176377d9STyler Hicks * 352176377d9STyler Hicks * IMPORTANT: Ownership of the allocated buffer is transferred from 353176377d9STyler Hicks * src_copy to the first element in the items array. To free the 354176377d9STyler Hicks * buffer, kfree() must only be called on the first element of the 355176377d9STyler Hicks * array. 356176377d9STyler Hicks */ 357176377d9STyler Hicks for (i = 0, cur = src_copy; i < count; i++) { 358176377d9STyler Hicks opt_list->items[i] = cur; 359176377d9STyler Hicks cur = strchr(cur, '\0') + 1; 360176377d9STyler Hicks } 361176377d9STyler Hicks 362176377d9STyler Hicks return opt_list; 363176377d9STyler Hicks } 364176377d9STyler Hicks 365176377d9STyler Hicks static void ima_free_rule_opt_list(struct ima_rule_opt_list *opt_list) 366176377d9STyler Hicks { 367176377d9STyler Hicks if (!opt_list) 368176377d9STyler Hicks return; 369176377d9STyler Hicks 370176377d9STyler Hicks if (opt_list->count) { 371176377d9STyler Hicks kfree(opt_list->items[0]); 372176377d9STyler Hicks opt_list->count = 0; 373176377d9STyler Hicks } 374176377d9STyler Hicks 375176377d9STyler Hicks kfree(opt_list); 376176377d9STyler Hicks } 377176377d9STyler Hicks 378b1694245SJanne Karhunen static void ima_lsm_free_rule(struct ima_rule_entry *entry) 3797163a993SMimi Zohar { 3807163a993SMimi Zohar int i; 3817163a993SMimi Zohar 382b1694245SJanne Karhunen for (i = 0; i < MAX_LSM_RULES; i++) { 383b8867eedSTyler Hicks ima_filter_rule_free(entry->lsm[i].rule); 384b1694245SJanne Karhunen kfree(entry->lsm[i].args_p); 385b1694245SJanne Karhunen } 386465aee77STyler Hicks } 387465aee77STyler Hicks 388465aee77STyler Hicks static void ima_free_rule(struct ima_rule_entry *entry) 389465aee77STyler Hicks { 390465aee77STyler Hicks if (!entry) 391465aee77STyler Hicks return; 392465aee77STyler Hicks 393465aee77STyler Hicks /* 394465aee77STyler Hicks * entry->template->fields may be allocated in ima_parse_rule() but that 395465aee77STyler Hicks * reference is owned by the corresponding ima_template_desc element in 396465aee77STyler Hicks * the defined_templates list and cannot be freed here 397465aee77STyler Hicks */ 398465aee77STyler Hicks kfree(entry->fsname); 399176377d9STyler Hicks ima_free_rule_opt_list(entry->keyrings); 400465aee77STyler Hicks ima_lsm_free_rule(entry); 401b1694245SJanne Karhunen kfree(entry); 402b1694245SJanne Karhunen } 403b1694245SJanne Karhunen 404*9a95c5bfSGUO Zihua static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry, 405*9a95c5bfSGUO Zihua gfp_t gfp) 406b1694245SJanne Karhunen { 407b1694245SJanne Karhunen struct ima_rule_entry *nentry; 408483ec26eSJanne Karhunen int i; 409b1694245SJanne Karhunen 410b1694245SJanne Karhunen /* 411b1694245SJanne Karhunen * Immutable elements are copied over as pointers and data; only 412b1694245SJanne Karhunen * lsm rules can change 413b1694245SJanne Karhunen */ 414*9a95c5bfSGUO Zihua nentry = kmemdup(entry, sizeof(*nentry), gfp); 415f60c826dSAlex Dewar if (!nentry) 416f60c826dSAlex Dewar return NULL; 417f60c826dSAlex Dewar 418c593642cSPankaj Bharadiya memset(nentry->lsm, 0, sizeof_field(struct ima_rule_entry, lsm)); 419b1694245SJanne Karhunen 4207163a993SMimi Zohar for (i = 0; i < MAX_LSM_RULES; i++) { 421483ec26eSJanne Karhunen if (!entry->lsm[i].args_p) 4227163a993SMimi Zohar continue; 423b1694245SJanne Karhunen 424b1694245SJanne Karhunen nentry->lsm[i].type = entry->lsm[i].type; 42539e5993dSTyler Hicks nentry->lsm[i].args_p = entry->lsm[i].args_p; 426b1694245SJanne Karhunen 427b8867eedSTyler Hicks ima_filter_rule_init(nentry->lsm[i].type, Audit_equal, 428b1694245SJanne Karhunen nentry->lsm[i].args_p, 429*9a95c5bfSGUO Zihua &nentry->lsm[i].rule, 430*9a95c5bfSGUO Zihua gfp); 431483ec26eSJanne Karhunen if (!nentry->lsm[i].rule) 432483ec26eSJanne Karhunen pr_warn("rule for LSM \'%s\' is undefined\n", 433aa0c0227STyler Hicks nentry->lsm[i].args_p); 434b1694245SJanne Karhunen } 435b1694245SJanne Karhunen return nentry; 436b1694245SJanne Karhunen } 437b1694245SJanne Karhunen 438b1694245SJanne Karhunen static int ima_lsm_update_rule(struct ima_rule_entry *entry) 439b1694245SJanne Karhunen { 440d57378d3SGUO Zihua int i; 441b1694245SJanne Karhunen struct ima_rule_entry *nentry; 442b1694245SJanne Karhunen 443*9a95c5bfSGUO Zihua nentry = ima_lsm_copy_rule(entry, GFP_KERNEL); 444b1694245SJanne Karhunen if (!nentry) 445b1694245SJanne Karhunen return -ENOMEM; 446b1694245SJanne Karhunen 447b1694245SJanne Karhunen list_replace_rcu(&entry->list, &nentry->list); 448b1694245SJanne Karhunen synchronize_rcu(); 449465aee77STyler Hicks /* 450465aee77STyler Hicks * ima_lsm_copy_rule() shallow copied all references, except for the 451465aee77STyler Hicks * LSM references, from entry to nentry so we only want to free the LSM 45265603435SAustin Kim * references and the entry itself. All other memory references will now 453465aee77STyler Hicks * be owned by nentry. 454465aee77STyler Hicks */ 455d57378d3SGUO Zihua for (i = 0; i < MAX_LSM_RULES; i++) 456d57378d3SGUO Zihua ima_filter_rule_free(entry->lsm[i].rule); 457465aee77STyler Hicks kfree(entry); 458b1694245SJanne Karhunen 459b1694245SJanne Karhunen return 0; 460b1694245SJanne Karhunen } 461b1694245SJanne Karhunen 462db2045f5STyler Hicks static bool ima_rule_contains_lsm_cond(struct ima_rule_entry *entry) 463db2045f5STyler Hicks { 464db2045f5STyler Hicks int i; 465db2045f5STyler Hicks 466db2045f5STyler Hicks for (i = 0; i < MAX_LSM_RULES; i++) 467db2045f5STyler Hicks if (entry->lsm[i].args_p) 468db2045f5STyler Hicks return true; 469db2045f5STyler Hicks 470db2045f5STyler Hicks return false; 471db2045f5STyler Hicks } 472db2045f5STyler Hicks 473b1694245SJanne Karhunen /* 474b1694245SJanne Karhunen * The LSM policy can be reloaded, leaving the IMA LSM based rules referring 475b1694245SJanne Karhunen * to the old, stale LSM policy. Update the IMA LSM based rules to reflect 476b1694245SJanne Karhunen * the reloaded LSM policy. 477b1694245SJanne Karhunen */ 478b1694245SJanne Karhunen static void ima_lsm_update_rules(void) 479b1694245SJanne Karhunen { 480b1694245SJanne Karhunen struct ima_rule_entry *entry, *e; 481592b24cbSTyler Hicks int result; 482b1694245SJanne Karhunen 483b1694245SJanne Karhunen list_for_each_entry_safe(entry, e, &ima_policy_rules, list) { 484592b24cbSTyler Hicks if (!ima_rule_contains_lsm_cond(entry)) 485b1694245SJanne Karhunen continue; 486b1694245SJanne Karhunen 487b1694245SJanne Karhunen result = ima_lsm_update_rule(entry); 488b1694245SJanne Karhunen if (result) { 489483ec26eSJanne Karhunen pr_err("lsm rule update error %d\n", result); 490b1694245SJanne Karhunen return; 491b1694245SJanne Karhunen } 492b1694245SJanne Karhunen } 493b1694245SJanne Karhunen } 494b1694245SJanne Karhunen 495b1694245SJanne Karhunen int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, 496b1694245SJanne Karhunen void *lsm_data) 497b1694245SJanne Karhunen { 498b1694245SJanne Karhunen if (event != LSM_POLICY_CHANGE) 499b1694245SJanne Karhunen return NOTIFY_DONE; 500b1694245SJanne Karhunen 501b1694245SJanne Karhunen ima_lsm_update_rules(); 502b1694245SJanne Karhunen return NOTIFY_OK; 5037163a993SMimi Zohar } 5047163a993SMimi Zohar 5053323eec9SMimi Zohar /** 5062b4a2474STushar Sugandhi * ima_match_rule_data - determine whether func_data matches the policy rule 507e9085e0aSLakshmi Ramasubramanian * @rule: a pointer to a rule 5082b4a2474STushar Sugandhi * @func_data: data to match against the measure rule data 509e9085e0aSLakshmi Ramasubramanian * @cred: a pointer to a credentials structure for user validation 510e9085e0aSLakshmi Ramasubramanian * 5112b4a2474STushar Sugandhi * Returns true if func_data matches one in the rule, false otherwise. 512e9085e0aSLakshmi Ramasubramanian */ 5132b4a2474STushar Sugandhi static bool ima_match_rule_data(struct ima_rule_entry *rule, 5142b4a2474STushar Sugandhi const char *func_data, 5152b4a2474STushar Sugandhi const struct cred *cred) 516e9085e0aSLakshmi Ramasubramanian { 5172b4a2474STushar Sugandhi const struct ima_rule_opt_list *opt_list = NULL; 518e9085e0aSLakshmi Ramasubramanian bool matched = false; 519176377d9STyler Hicks size_t i; 520e9085e0aSLakshmi Ramasubramanian 521e9085e0aSLakshmi Ramasubramanian if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid)) 522e9085e0aSLakshmi Ramasubramanian return false; 523e9085e0aSLakshmi Ramasubramanian 5242b4a2474STushar Sugandhi switch (rule->func) { 5252b4a2474STushar Sugandhi case KEY_CHECK: 526e9085e0aSLakshmi Ramasubramanian if (!rule->keyrings) 527e9085e0aSLakshmi Ramasubramanian return true; 528e9085e0aSLakshmi Ramasubramanian 5292b4a2474STushar Sugandhi opt_list = rule->keyrings; 5302b4a2474STushar Sugandhi break; 531c4e43aa2STushar Sugandhi case CRITICAL_DATA: 53247d76a48STushar Sugandhi if (!rule->label) 533c4e43aa2STushar Sugandhi return true; 53447d76a48STushar Sugandhi 53547d76a48STushar Sugandhi opt_list = rule->label; 53647d76a48STushar Sugandhi break; 5372b4a2474STushar Sugandhi default: 5382b4a2474STushar Sugandhi return false; 5392b4a2474STushar Sugandhi } 5402b4a2474STushar Sugandhi 5412b4a2474STushar Sugandhi if (!func_data) 542e9085e0aSLakshmi Ramasubramanian return false; 543e9085e0aSLakshmi Ramasubramanian 5442b4a2474STushar Sugandhi for (i = 0; i < opt_list->count; i++) { 5452b4a2474STushar Sugandhi if (!strcmp(opt_list->items[i], func_data)) { 546e9085e0aSLakshmi Ramasubramanian matched = true; 547e9085e0aSLakshmi Ramasubramanian break; 548e9085e0aSLakshmi Ramasubramanian } 549e9085e0aSLakshmi Ramasubramanian } 550e9085e0aSLakshmi Ramasubramanian 551e9085e0aSLakshmi Ramasubramanian return matched; 552e9085e0aSLakshmi Ramasubramanian } 553e9085e0aSLakshmi Ramasubramanian 554e9085e0aSLakshmi Ramasubramanian /** 555483ec26eSJanne Karhunen * ima_match_rules - determine whether an inode matches the policy rule. 5563323eec9SMimi Zohar * @rule: a pointer to a rule 55739f60c1cSChristian Brauner * @idmap: idmap of the mount the inode was found from 5583323eec9SMimi Zohar * @inode: a pointer to an inode 559d906c10dSMatthew Garrett * @cred: a pointer to a credentials structure for user validation 560d906c10dSMatthew Garrett * @secid: the secid of the task to be validated 5613323eec9SMimi Zohar * @func: LIM hook identifier 5623323eec9SMimi Zohar * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) 5632b4a2474STushar Sugandhi * @func_data: func specific data, may be NULL 5643323eec9SMimi Zohar * 5653323eec9SMimi Zohar * Returns true on rule match, false on failure. 5663323eec9SMimi Zohar */ 567a2d2329eSChristian Brauner static bool ima_match_rules(struct ima_rule_entry *rule, 56839f60c1cSChristian Brauner struct mnt_idmap *idmap, 569a2d2329eSChristian Brauner struct inode *inode, const struct cred *cred, 570a2d2329eSChristian Brauner u32 secid, enum ima_hooks func, int mask, 5712b4a2474STushar Sugandhi const char *func_data) 5723323eec9SMimi Zohar { 5734af4662fSMimi Zohar int i; 574c7423dbdSGUO Zihua bool result = false; 575c7423dbdSGUO Zihua struct ima_rule_entry *lsm_rule = rule; 576c7423dbdSGUO Zihua bool rule_reinitialized = false; 5773323eec9SMimi Zohar 57809b1148eSDmitry Kasatkin if ((rule->flags & IMA_FUNC) && 57909b1148eSDmitry Kasatkin (rule->func != func && func != POST_SETATTR)) 5803323eec9SMimi Zohar return false; 581c4e43aa2STushar Sugandhi 582c4e43aa2STushar Sugandhi switch (func) { 583c4e43aa2STushar Sugandhi case KEY_CHECK: 584c4e43aa2STushar Sugandhi case CRITICAL_DATA: 585c4e43aa2STushar Sugandhi return ((rule->func == func) && 586c4e43aa2STushar Sugandhi ima_match_rule_data(rule, func_data, cred)); 587c4e43aa2STushar Sugandhi default: 588c4e43aa2STushar Sugandhi break; 589c4e43aa2STushar Sugandhi } 590c4e43aa2STushar Sugandhi 59109b1148eSDmitry Kasatkin if ((rule->flags & IMA_MASK) && 59209b1148eSDmitry Kasatkin (rule->mask != mask && func != POST_SETATTR)) 5933323eec9SMimi Zohar return false; 5944351c294SMimi Zohar if ((rule->flags & IMA_INMASK) && 5954351c294SMimi Zohar (!(rule->mask & mask) && func != POST_SETATTR)) 5964351c294SMimi Zohar return false; 5973323eec9SMimi Zohar if ((rule->flags & IMA_FSMAGIC) 5983323eec9SMimi Zohar && rule->fsmagic != inode->i_sb->s_magic) 5993323eec9SMimi Zohar return false; 600f1b08bbcSMimi Zohar if ((rule->flags & IMA_FSNAME) 601f1b08bbcSMimi Zohar && strcmp(rule->fsname, inode->i_sb->s_type->name)) 602f1b08bbcSMimi Zohar return false; 60385865c1fSDmitry Kasatkin if ((rule->flags & IMA_FSUUID) && 60485787090SChristoph Hellwig !uuid_equal(&rule->fsuuid, &inode->i_sb->s_uuid)) 60585865c1fSDmitry Kasatkin return false; 6063dd0c8d0SMikhail Kurinnoi if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid)) 6073323eec9SMimi Zohar return false; 608139069efSMimi Zohar if (rule->flags & IMA_EUID) { 609139069efSMimi Zohar if (has_capability_noaudit(current, CAP_SETUID)) { 6103dd0c8d0SMikhail Kurinnoi if (!rule->uid_op(cred->euid, rule->uid) 6113dd0c8d0SMikhail Kurinnoi && !rule->uid_op(cred->suid, rule->uid) 6123dd0c8d0SMikhail Kurinnoi && !rule->uid_op(cred->uid, rule->uid)) 613139069efSMimi Zohar return false; 6143dd0c8d0SMikhail Kurinnoi } else if (!rule->uid_op(cred->euid, rule->uid)) 615139069efSMimi Zohar return false; 616139069efSMimi Zohar } 61740224c41SCurtis Veit if ((rule->flags & IMA_GID) && !rule->gid_op(cred->gid, rule->gid)) 61840224c41SCurtis Veit return false; 61940224c41SCurtis Veit if (rule->flags & IMA_EGID) { 62040224c41SCurtis Veit if (has_capability_noaudit(current, CAP_SETGID)) { 62140224c41SCurtis Veit if (!rule->gid_op(cred->egid, rule->gid) 62240224c41SCurtis Veit && !rule->gid_op(cred->sgid, rule->gid) 62340224c41SCurtis Veit && !rule->gid_op(cred->gid, rule->gid)) 62440224c41SCurtis Veit return false; 62540224c41SCurtis Veit } else if (!rule->gid_op(cred->egid, rule->gid)) 62640224c41SCurtis Veit return false; 62740224c41SCurtis Veit } 6283dd0c8d0SMikhail Kurinnoi if ((rule->flags & IMA_FOWNER) && 629e67fe633SChristian Brauner !rule->fowner_op(i_uid_into_vfsuid(idmap, inode), 6308e27a7aeSChristian Brauner rule->fowner)) 63107f6a794SMimi Zohar return false; 63240224c41SCurtis Veit if ((rule->flags & IMA_FGROUP) && 633e67fe633SChristian Brauner !rule->fgroup_op(i_gid_into_vfsgid(idmap, inode), 6348e27a7aeSChristian Brauner rule->fgroup)) 63540224c41SCurtis Veit return false; 6364af4662fSMimi Zohar for (i = 0; i < MAX_LSM_RULES; i++) { 63753fc0e22SMimi Zohar int rc = 0; 638d906c10dSMatthew Garrett u32 osid; 6394af4662fSMimi Zohar 640c7423dbdSGUO Zihua if (!lsm_rule->lsm[i].rule) { 641c7423dbdSGUO Zihua if (!lsm_rule->lsm[i].args_p) 6424af4662fSMimi Zohar continue; 643483ec26eSJanne Karhunen else 644483ec26eSJanne Karhunen return false; 645483ec26eSJanne Karhunen } 646c7423dbdSGUO Zihua 647c7423dbdSGUO Zihua retry: 6484af4662fSMimi Zohar switch (i) { 6494af4662fSMimi Zohar case LSM_OBJ_USER: 6504af4662fSMimi Zohar case LSM_OBJ_ROLE: 6514af4662fSMimi Zohar case LSM_OBJ_TYPE: 6524af4662fSMimi Zohar security_inode_getsecid(inode, &osid); 653c7423dbdSGUO Zihua rc = ima_filter_rule_match(osid, lsm_rule->lsm[i].type, 65453fc0e22SMimi Zohar Audit_equal, 655c7423dbdSGUO Zihua lsm_rule->lsm[i].rule); 6564af4662fSMimi Zohar break; 6574af4662fSMimi Zohar case LSM_SUBJ_USER: 6584af4662fSMimi Zohar case LSM_SUBJ_ROLE: 6594af4662fSMimi Zohar case LSM_SUBJ_TYPE: 660c7423dbdSGUO Zihua rc = ima_filter_rule_match(secid, lsm_rule->lsm[i].type, 66153fc0e22SMimi Zohar Audit_equal, 662c7423dbdSGUO Zihua lsm_rule->lsm[i].rule); 66328073eb0SGustavo A. R. Silva break; 6644af4662fSMimi Zohar default: 6654af4662fSMimi Zohar break; 6664af4662fSMimi Zohar } 667c7423dbdSGUO Zihua 668c7423dbdSGUO Zihua if (rc == -ESTALE && !rule_reinitialized) { 669*9a95c5bfSGUO Zihua lsm_rule = ima_lsm_copy_rule(rule, GFP_ATOMIC); 670c7423dbdSGUO Zihua if (lsm_rule) { 671c7423dbdSGUO Zihua rule_reinitialized = true; 672c7423dbdSGUO Zihua goto retry; 6734af4662fSMimi Zohar } 674c7423dbdSGUO Zihua } 675c7423dbdSGUO Zihua if (!rc) { 676c7423dbdSGUO Zihua result = false; 677c7423dbdSGUO Zihua goto out; 678c7423dbdSGUO Zihua } 679c7423dbdSGUO Zihua } 680c7423dbdSGUO Zihua result = true; 681c7423dbdSGUO Zihua 682c7423dbdSGUO Zihua out: 683c7423dbdSGUO Zihua if (rule_reinitialized) { 684c7423dbdSGUO Zihua for (i = 0; i < MAX_LSM_RULES; i++) 685c7423dbdSGUO Zihua ima_filter_rule_free(lsm_rule->lsm[i].rule); 686c7423dbdSGUO Zihua kfree(lsm_rule); 687c7423dbdSGUO Zihua } 688c7423dbdSGUO Zihua return result; 6893323eec9SMimi Zohar } 6903323eec9SMimi Zohar 691d79d72e0SMimi Zohar /* 692d79d72e0SMimi Zohar * In addition to knowing that we need to appraise the file in general, 6935a73fcfaSMimi Zohar * we need to differentiate between calling hooks, for hook specific rules. 694d79d72e0SMimi Zohar */ 6954ad87a3dSMimi Zohar static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) 696d79d72e0SMimi Zohar { 6975a73fcfaSMimi Zohar if (!(rule->flags & IMA_FUNC)) 6985a73fcfaSMimi Zohar return IMA_FILE_APPRAISE; 6995a73fcfaSMimi Zohar 700d79d72e0SMimi Zohar switch (func) { 701d79d72e0SMimi Zohar case MMAP_CHECK: 7024958db32SRoberto Sassu case MMAP_CHECK_REQPROT: 703d79d72e0SMimi Zohar return IMA_MMAP_APPRAISE; 704d79d72e0SMimi Zohar case BPRM_CHECK: 705d79d72e0SMimi Zohar return IMA_BPRM_APPRAISE; 706d906c10dSMatthew Garrett case CREDS_CHECK: 707d906c10dSMatthew Garrett return IMA_CREDS_APPRAISE; 708d79d72e0SMimi Zohar case FILE_CHECK: 709c6af8efeSMimi Zohar case POST_SETATTR: 710d79d72e0SMimi Zohar return IMA_FILE_APPRAISE; 711c6af8efeSMimi Zohar case MODULE_CHECK ... MAX_CHECK - 1: 712c6af8efeSMimi Zohar default: 713c6af8efeSMimi Zohar return IMA_READ_APPRAISE; 714d79d72e0SMimi Zohar } 715d79d72e0SMimi Zohar } 716d79d72e0SMimi Zohar 7173323eec9SMimi Zohar /** 7183323eec9SMimi Zohar * ima_match_policy - decision based on LSM and other conditions 71939f60c1cSChristian Brauner * @idmap: idmap of the mount the inode was found from 7203323eec9SMimi Zohar * @inode: pointer to an inode for which the policy decision is being made 721d906c10dSMatthew Garrett * @cred: pointer to a credentials structure for which the policy decision is 722d906c10dSMatthew Garrett * being made 723d906c10dSMatthew Garrett * @secid: LSM secid of the task to be validated 7243323eec9SMimi Zohar * @func: IMA hook identifier 7253323eec9SMimi Zohar * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) 72695526d13SRoberto Sassu * @flags: IMA actions to consider (e.g. IMA_MEASURE | IMA_APPRAISE) 727725de7faSEric Richter * @pcr: set the pcr to extend 72819453ce0SMatthew Garrett * @template_desc: the template that should be used for this rule 7292b4a2474STushar Sugandhi * @func_data: func specific data, may be NULL 7301624dc00STHOBY Simon * @allowed_algos: allowlist of hash algorithms for the IMA xattr 7313323eec9SMimi Zohar * 7323323eec9SMimi Zohar * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) 7333323eec9SMimi Zohar * conditions. 7343323eec9SMimi Zohar * 73538d859f9SPetko Manolov * Since the IMA policy may be updated multiple times we need to lock the 73638d859f9SPetko Manolov * list when walking it. Reads are many orders of magnitude more numerous 73738d859f9SPetko Manolov * than writes so ima_match_policy() is classical RCU candidate. 7383323eec9SMimi Zohar */ 73939f60c1cSChristian Brauner int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode, 740a2d2329eSChristian Brauner const struct cred *cred, u32 secid, enum ima_hooks func, 741a2d2329eSChristian Brauner int mask, int flags, int *pcr, 742e9085e0aSLakshmi Ramasubramanian struct ima_template_desc **template_desc, 7431624dc00STHOBY Simon const char *func_data, unsigned int *allowed_algos) 7443323eec9SMimi Zohar { 74507f6a794SMimi Zohar struct ima_rule_entry *entry; 7462fe5d6deSMimi Zohar int action = 0, actmask = flags | (flags << 1); 747eb0782bbSliqiong struct list_head *ima_rules_tmp; 7483323eec9SMimi Zohar 749dea87d08SLakshmi Ramasubramanian if (template_desc && !*template_desc) 750b36f281fSMimi Zohar *template_desc = ima_template_desc_current(); 751b36f281fSMimi Zohar 75238d859f9SPetko Manolov rcu_read_lock(); 753eb0782bbSliqiong ima_rules_tmp = rcu_dereference(ima_rules); 754eb0782bbSliqiong list_for_each_entry_rcu(entry, ima_rules_tmp, list) { 7553323eec9SMimi Zohar 7562fe5d6deSMimi Zohar if (!(entry->action & actmask)) 7572fe5d6deSMimi Zohar continue; 7582fe5d6deSMimi Zohar 75939f60c1cSChristian Brauner if (!ima_match_rules(entry, idmap, inode, cred, secid, 7607d6beb71SLinus Torvalds func, mask, func_data)) 7612fe5d6deSMimi Zohar continue; 7622fe5d6deSMimi Zohar 763aae6ccbdSMimi Zohar action |= entry->flags & IMA_NONACTION_FLAGS; 7640e5a247cSDmitry Kasatkin 76545e2472eSDmitry Kasatkin action |= entry->action & IMA_DO_MASK; 766da1b0029SMimi Zohar if (entry->action & IMA_APPRAISE) { 7675a73fcfaSMimi Zohar action |= get_subaction(entry, func); 768a9a4935dSMimi Zohar action &= ~IMA_HASH; 7699e67028eSMimi Zohar if (ima_fail_unverifiable_sigs) 7709e67028eSMimi Zohar action |= IMA_FAIL_UNVERIFIABLE_SIGS; 771d79d72e0SMimi Zohar 7721624dc00STHOBY Simon if (allowed_algos && 7731624dc00STHOBY Simon entry->flags & IMA_VALIDATE_ALGOS) 7741624dc00STHOBY Simon *allowed_algos = entry->allowed_algos; 7751624dc00STHOBY Simon } 776b36f281fSMimi Zohar 77745e2472eSDmitry Kasatkin if (entry->action & IMA_DO_MASK) 77845e2472eSDmitry Kasatkin actmask &= ~(entry->action | entry->action << 1); 77945e2472eSDmitry Kasatkin else 78045e2472eSDmitry Kasatkin actmask &= ~(entry->action | entry->action >> 1); 78145e2472eSDmitry Kasatkin 782725de7faSEric Richter if ((pcr) && (entry->flags & IMA_PCR)) 783725de7faSEric Richter *pcr = entry->pcr; 784725de7faSEric Richter 78519453ce0SMatthew Garrett if (template_desc && entry->template) 78619453ce0SMatthew Garrett *template_desc = entry->template; 78719453ce0SMatthew Garrett 7882fe5d6deSMimi Zohar if (!actmask) 7892fe5d6deSMimi Zohar break; 7903323eec9SMimi Zohar } 79138d859f9SPetko Manolov rcu_read_unlock(); 7922fe5d6deSMimi Zohar 7932fe5d6deSMimi Zohar return action; 7943323eec9SMimi Zohar } 7953323eec9SMimi Zohar 7964f2946aaSTHOBY Simon /** 7974f2946aaSTHOBY Simon * ima_update_policy_flags() - Update global IMA variables 7984f2946aaSTHOBY Simon * 7994f2946aaSTHOBY Simon * Update ima_policy_flag and ima_setxattr_allowed_hash_algorithms 8004f2946aaSTHOBY Simon * based on the currently loaded policy. 8014f2946aaSTHOBY Simon * 8024f2946aaSTHOBY Simon * With ima_policy_flag, the decision to short circuit out of a function 8034f2946aaSTHOBY Simon * or not call the function in the first place can be made earlier. 8044f2946aaSTHOBY Simon * 8054f2946aaSTHOBY Simon * With ima_setxattr_allowed_hash_algorithms, the policy can restrict the 8064f2946aaSTHOBY Simon * set of hash algorithms accepted when updating the security.ima xattr of 8074f2946aaSTHOBY Simon * a file. 8084f2946aaSTHOBY Simon * 8094f2946aaSTHOBY Simon * Context: called after a policy update and at system initialization. 810a756024eSRoberto Sassu */ 8114f2946aaSTHOBY Simon void ima_update_policy_flags(void) 812a756024eSRoberto Sassu { 813a756024eSRoberto Sassu struct ima_rule_entry *entry; 8144f2946aaSTHOBY Simon int new_policy_flag = 0; 815eb0782bbSliqiong struct list_head *ima_rules_tmp; 816a756024eSRoberto Sassu 8174f2946aaSTHOBY Simon rcu_read_lock(); 818eb0782bbSliqiong ima_rules_tmp = rcu_dereference(ima_rules); 819eb0782bbSliqiong list_for_each_entry_rcu(entry, ima_rules_tmp, list) { 8204f2946aaSTHOBY Simon /* 8214f2946aaSTHOBY Simon * SETXATTR_CHECK rules do not implement a full policy check 8224f2946aaSTHOBY Simon * because rule checking would probably have an important 8234f2946aaSTHOBY Simon * performance impact on setxattr(). As a consequence, only one 8244f2946aaSTHOBY Simon * SETXATTR_CHECK can be active at a given time. 8254f2946aaSTHOBY Simon * Because we want to preserve that property, we set out to use 8264f2946aaSTHOBY Simon * atomic_cmpxchg. Either: 8274f2946aaSTHOBY Simon * - the atomic was non-zero: a setxattr hash policy is 8284f2946aaSTHOBY Simon * already enforced, we do nothing 8294f2946aaSTHOBY Simon * - the atomic was zero: no setxattr policy was set, enable 8304f2946aaSTHOBY Simon * the setxattr hash policy 8314f2946aaSTHOBY Simon */ 8324f2946aaSTHOBY Simon if (entry->func == SETXATTR_CHECK) { 8334f2946aaSTHOBY Simon atomic_cmpxchg(&ima_setxattr_allowed_hash_algorithms, 8344f2946aaSTHOBY Simon 0, entry->allowed_algos); 8354f2946aaSTHOBY Simon /* SETXATTR_CHECK doesn't impact ima_policy_flag */ 8364f2946aaSTHOBY Simon continue; 837a756024eSRoberto Sassu } 838a756024eSRoberto Sassu 8394f2946aaSTHOBY Simon if (entry->action & IMA_DO_MASK) 8404f2946aaSTHOBY Simon new_policy_flag |= entry->action; 8414f2946aaSTHOBY Simon } 8424f2946aaSTHOBY Simon rcu_read_unlock(); 8434f2946aaSTHOBY Simon 844ef96837bSMimi Zohar ima_appraise |= (build_ima_appraise | temp_ima_appraise); 845a756024eSRoberto Sassu if (!ima_appraise) 8464f2946aaSTHOBY Simon new_policy_flag &= ~IMA_APPRAISE; 8474f2946aaSTHOBY Simon 8484f2946aaSTHOBY Simon ima_policy_flag = new_policy_flag; 849a756024eSRoberto Sassu } 850a756024eSRoberto Sassu 8516f0911a6SMimi Zohar static int ima_appraise_flag(enum ima_hooks func) 8526f0911a6SMimi Zohar { 8536f0911a6SMimi Zohar if (func == MODULE_CHECK) 8546f0911a6SMimi Zohar return IMA_APPRAISE_MODULES; 8556f0911a6SMimi Zohar else if (func == FIRMWARE_CHECK) 8566f0911a6SMimi Zohar return IMA_APPRAISE_FIRMWARE; 8576f0911a6SMimi Zohar else if (func == POLICY_CHECK) 8586f0911a6SMimi Zohar return IMA_APPRAISE_POLICY; 85916c267aaSMimi Zohar else if (func == KEXEC_KERNEL_CHECK) 86016c267aaSMimi Zohar return IMA_APPRAISE_KEXEC; 8616f0911a6SMimi Zohar return 0; 8626f0911a6SMimi Zohar } 8636f0911a6SMimi Zohar 864c52657d9SNayna Jain static void add_rules(struct ima_rule_entry *entries, int count, 865c52657d9SNayna Jain enum policy_rule_list policy_rule) 866c52657d9SNayna Jain { 867c52657d9SNayna Jain int i = 0; 868c52657d9SNayna Jain 869c52657d9SNayna Jain for (i = 0; i < count; i++) { 870c52657d9SNayna Jain struct ima_rule_entry *entry; 871c52657d9SNayna Jain 872c52657d9SNayna Jain if (policy_rule & IMA_DEFAULT_POLICY) 873c52657d9SNayna Jain list_add_tail(&entries[i].list, &ima_default_rules); 874c52657d9SNayna Jain 875c52657d9SNayna Jain if (policy_rule & IMA_CUSTOM_POLICY) { 876c52657d9SNayna Jain entry = kmemdup(&entries[i], sizeof(*entry), 877c52657d9SNayna Jain GFP_KERNEL); 878c52657d9SNayna Jain if (!entry) 879c52657d9SNayna Jain continue; 880c52657d9SNayna Jain 881c52657d9SNayna Jain list_add_tail(&entry->list, &ima_policy_rules); 882c52657d9SNayna Jain } 883b59fda44SKrzysztof Struczynski if (entries[i].action == APPRAISE) { 884b59fda44SKrzysztof Struczynski if (entries != build_appraise_rules) 885b59fda44SKrzysztof Struczynski temp_ima_appraise |= 886b59fda44SKrzysztof Struczynski ima_appraise_flag(entries[i].func); 887b59fda44SKrzysztof Struczynski else 888b59fda44SKrzysztof Struczynski build_ima_appraise |= 889b59fda44SKrzysztof Struczynski ima_appraise_flag(entries[i].func); 890b59fda44SKrzysztof Struczynski } 891c52657d9SNayna Jain } 892f4001947SPetr Vorel } 893c52657d9SNayna Jain 89461917062SNayna Jain static int ima_parse_rule(char *rule, struct ima_rule_entry *entry); 89561917062SNayna Jain 89661917062SNayna Jain static int __init ima_init_arch_policy(void) 89761917062SNayna Jain { 89861917062SNayna Jain const char * const *arch_rules; 89961917062SNayna Jain const char * const *rules; 90061917062SNayna Jain int arch_entries = 0; 90161917062SNayna Jain int i = 0; 90261917062SNayna Jain 90361917062SNayna Jain arch_rules = arch_get_ima_policy(); 90461917062SNayna Jain if (!arch_rules) 90561917062SNayna Jain return arch_entries; 90661917062SNayna Jain 90761917062SNayna Jain /* Get number of rules */ 90861917062SNayna Jain for (rules = arch_rules; *rules != NULL; rules++) 90961917062SNayna Jain arch_entries++; 91061917062SNayna Jain 91161917062SNayna Jain arch_policy_entry = kcalloc(arch_entries + 1, 91261917062SNayna Jain sizeof(*arch_policy_entry), GFP_KERNEL); 91361917062SNayna Jain if (!arch_policy_entry) 91461917062SNayna Jain return 0; 91561917062SNayna Jain 91661917062SNayna Jain /* Convert each policy string rules to struct ima_rule_entry format */ 91761917062SNayna Jain for (rules = arch_rules, i = 0; *rules != NULL; rules++) { 91861917062SNayna Jain char rule[255]; 91961917062SNayna Jain int result; 92061917062SNayna Jain 921cc4299eaSPetr Vorel result = strscpy(rule, *rules, sizeof(rule)); 92261917062SNayna Jain 92361917062SNayna Jain INIT_LIST_HEAD(&arch_policy_entry[i].list); 92461917062SNayna Jain result = ima_parse_rule(rule, &arch_policy_entry[i]); 92561917062SNayna Jain if (result) { 92661917062SNayna Jain pr_warn("Skipping unknown architecture policy rule: %s\n", 92761917062SNayna Jain rule); 92861917062SNayna Jain memset(&arch_policy_entry[i], 0, 92961917062SNayna Jain sizeof(*arch_policy_entry)); 93061917062SNayna Jain continue; 93161917062SNayna Jain } 93261917062SNayna Jain i++; 93361917062SNayna Jain } 93461917062SNayna Jain return i; 93561917062SNayna Jain } 93661917062SNayna Jain 9373323eec9SMimi Zohar /** 9383323eec9SMimi Zohar * ima_init_policy - initialize the default measure rules. 9393323eec9SMimi Zohar * 94061868acbSPetr Vorel * ima_rules points to either the ima_default_rules or the new ima_policy_rules. 9413323eec9SMimi Zohar */ 942932995f0SEric Paris void __init ima_init_policy(void) 9433323eec9SMimi Zohar { 94461917062SNayna Jain int build_appraise_entries, arch_entries; 9453323eec9SMimi Zohar 946c52657d9SNayna Jain /* if !ima_policy, we load NO default rules */ 947c52657d9SNayna Jain if (ima_policy) 948c52657d9SNayna Jain add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules), 949c52657d9SNayna Jain IMA_DEFAULT_POLICY); 95024fd03c8SMimi Zohar 95124fd03c8SMimi Zohar switch (ima_policy) { 95224fd03c8SMimi Zohar case ORIGINAL_TCB: 953c52657d9SNayna Jain add_rules(original_measurement_rules, 954c52657d9SNayna Jain ARRAY_SIZE(original_measurement_rules), 955c52657d9SNayna Jain IMA_DEFAULT_POLICY); 95624fd03c8SMimi Zohar break; 95724fd03c8SMimi Zohar case DEFAULT_TCB: 958c52657d9SNayna Jain add_rules(default_measurement_rules, 959c52657d9SNayna Jain ARRAY_SIZE(default_measurement_rules), 960c52657d9SNayna Jain IMA_DEFAULT_POLICY); 96128073eb0SGustavo A. R. Silva break; 96224fd03c8SMimi Zohar default: 96324fd03c8SMimi Zohar break; 96424fd03c8SMimi Zohar } 96507f6a794SMimi Zohar 966503ceaefSMimi Zohar /* 96761917062SNayna Jain * Based on runtime secure boot flags, insert arch specific measurement 96861917062SNayna Jain * and appraise rules requiring file signatures for both the initial 96961917062SNayna Jain * and custom policies, prior to other appraise rules. 97061917062SNayna Jain * (Highest priority) 971503ceaefSMimi Zohar */ 97261917062SNayna Jain arch_entries = ima_init_arch_policy(); 97361917062SNayna Jain if (!arch_entries) 97461917062SNayna Jain pr_info("No architecture policies found\n"); 97561917062SNayna Jain else 97661917062SNayna Jain add_rules(arch_policy_entry, arch_entries, 97761917062SNayna Jain IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); 97861917062SNayna Jain 97961917062SNayna Jain /* 980503ceaefSMimi Zohar * Insert the builtin "secure_boot" policy rules requiring file 98161917062SNayna Jain * signatures, prior to other appraise rules. 982503ceaefSMimi Zohar */ 983c52657d9SNayna Jain if (ima_use_secure_boot) 984c52657d9SNayna Jain add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules), 985c52657d9SNayna Jain IMA_DEFAULT_POLICY); 986503ceaefSMimi Zohar 987ef96837bSMimi Zohar /* 988ef96837bSMimi Zohar * Insert the build time appraise rules requiring file signatures 989ef96837bSMimi Zohar * for both the initial and custom policies, prior to other appraise 990c52657d9SNayna Jain * rules. As the secure boot rules includes all of the build time 991c52657d9SNayna Jain * rules, include either one or the other set of rules, but not both. 992ef96837bSMimi Zohar */ 993c52657d9SNayna Jain build_appraise_entries = ARRAY_SIZE(build_appraise_rules); 994c52657d9SNayna Jain if (build_appraise_entries) { 995c52657d9SNayna Jain if (ima_use_secure_boot) 996c52657d9SNayna Jain add_rules(build_appraise_rules, build_appraise_entries, 997c52657d9SNayna Jain IMA_CUSTOM_POLICY); 998c52657d9SNayna Jain else 999c52657d9SNayna Jain add_rules(build_appraise_rules, build_appraise_entries, 1000c52657d9SNayna Jain IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); 1001ef96837bSMimi Zohar } 1002ef96837bSMimi Zohar 1003c52657d9SNayna Jain if (ima_use_appraise_tcb) 1004c52657d9SNayna Jain add_rules(default_appraise_rules, 1005c52657d9SNayna Jain ARRAY_SIZE(default_appraise_rules), 1006c52657d9SNayna Jain IMA_DEFAULT_POLICY); 100707f6a794SMimi Zohar 100803cee168SLakshmi Ramasubramanian if (ima_use_critical_data) 100903cee168SLakshmi Ramasubramanian add_rules(critical_data_rules, 101003cee168SLakshmi Ramasubramanian ARRAY_SIZE(critical_data_rules), 101103cee168SLakshmi Ramasubramanian IMA_DEFAULT_POLICY); 101203cee168SLakshmi Ramasubramanian 10134f2946aaSTHOBY Simon atomic_set(&ima_setxattr_allowed_hash_algorithms, 0); 10144f2946aaSTHOBY Simon 10154f2946aaSTHOBY Simon ima_update_policy_flags(); 10163323eec9SMimi Zohar } 10174af4662fSMimi Zohar 10180112721dSSasha Levin /* Make sure we have a valid policy, at least containing some rules. */ 1019c75d8e96SColin Ian King int ima_check_policy(void) 10200112721dSSasha Levin { 10210112721dSSasha Levin if (list_empty(&ima_temp_rules)) 10220112721dSSasha Levin return -EINVAL; 10230112721dSSasha Levin return 0; 10240112721dSSasha Levin } 10250112721dSSasha Levin 10264af4662fSMimi Zohar /** 10274af4662fSMimi Zohar * ima_update_policy - update default_rules with new measure rules 10284af4662fSMimi Zohar * 10294af4662fSMimi Zohar * Called on file .release to update the default rules with a complete new 103038d859f9SPetko Manolov * policy. What we do here is to splice ima_policy_rules and ima_temp_rules so 103138d859f9SPetko Manolov * they make a queue. The policy may be updated multiple times and this is the 103238d859f9SPetko Manolov * RCU updater. 103338d859f9SPetko Manolov * 103438d859f9SPetko Manolov * Policy rules are never deleted so ima_policy_flag gets zeroed only once when 103538d859f9SPetko Manolov * we switch from the default policy to user defined. 10364af4662fSMimi Zohar */ 10374af4662fSMimi Zohar void ima_update_policy(void) 10384af4662fSMimi Zohar { 103953b626f9SPetko Manolov struct list_head *policy = &ima_policy_rules; 104038d859f9SPetko Manolov 104153b626f9SPetko Manolov list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu); 104238d859f9SPetko Manolov 1043eb0782bbSliqiong if (ima_rules != (struct list_head __rcu *)policy) { 104438d859f9SPetko Manolov ima_policy_flag = 0; 104561917062SNayna Jain 1046eb0782bbSliqiong rcu_assign_pointer(ima_rules, policy); 104761917062SNayna Jain /* 104861917062SNayna Jain * IMA architecture specific policy rules are specified 104961917062SNayna Jain * as strings and converted to an array of ima_entry_rules 105061917062SNayna Jain * on boot. After loading a custom policy, free the 105161917062SNayna Jain * architecture specific rules stored as an array. 105261917062SNayna Jain */ 105361917062SNayna Jain kfree(arch_policy_entry); 105438d859f9SPetko Manolov } 10554f2946aaSTHOBY Simon ima_update_policy_flags(); 1056450d0fd5SLakshmi Ramasubramanian 1057450d0fd5SLakshmi Ramasubramanian /* Custom IMA policy has been loaded */ 1058450d0fd5SLakshmi Ramasubramanian ima_process_queued_keys(); 10594af4662fSMimi Zohar } 10604af4662fSMimi Zohar 10611a9430dbSMimi Zohar /* Keep the enumeration in sync with the policy_tokens! */ 106240224c41SCurtis Veit enum policy_opt { 10631a9430dbSMimi Zohar Opt_measure, Opt_dont_measure, 106407f6a794SMimi Zohar Opt_appraise, Opt_dont_appraise, 1065da1b0029SMimi Zohar Opt_audit, Opt_hash, Opt_dont_hash, 10664af4662fSMimi Zohar Opt_obj_user, Opt_obj_role, Opt_obj_type, 10674af4662fSMimi Zohar Opt_subj_user, Opt_subj_role, Opt_subj_type, 106840224c41SCurtis Veit Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname, Opt_fsuuid, 106940224c41SCurtis Veit Opt_uid_eq, Opt_euid_eq, Opt_gid_eq, Opt_egid_eq, 107040224c41SCurtis Veit Opt_fowner_eq, Opt_fgroup_eq, 107140224c41SCurtis Veit Opt_uid_gt, Opt_euid_gt, Opt_gid_gt, Opt_egid_gt, 107240224c41SCurtis Veit Opt_fowner_gt, Opt_fgroup_gt, 107340224c41SCurtis Veit Opt_uid_lt, Opt_euid_lt, Opt_gid_lt, Opt_egid_lt, 107440224c41SCurtis Veit Opt_fowner_lt, Opt_fgroup_lt, 107554f03916SMimi Zohar Opt_digest_type, 1076583a80aeSTHOBY Simon Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos, 10772b60c0ecSLakshmi Ramasubramanian Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings, 107847d76a48STushar Sugandhi Opt_label, Opt_err 10794af4662fSMimi Zohar }; 10804af4662fSMimi Zohar 10811a9430dbSMimi Zohar static const match_table_t policy_tokens = { 10824af4662fSMimi Zohar {Opt_measure, "measure"}, 10834af4662fSMimi Zohar {Opt_dont_measure, "dont_measure"}, 108407f6a794SMimi Zohar {Opt_appraise, "appraise"}, 108507f6a794SMimi Zohar {Opt_dont_appraise, "dont_appraise"}, 1086e7c568e0SPeter Moody {Opt_audit, "audit"}, 1087da1b0029SMimi Zohar {Opt_hash, "hash"}, 1088da1b0029SMimi Zohar {Opt_dont_hash, "dont_hash"}, 10894af4662fSMimi Zohar {Opt_obj_user, "obj_user=%s"}, 10904af4662fSMimi Zohar {Opt_obj_role, "obj_role=%s"}, 10914af4662fSMimi Zohar {Opt_obj_type, "obj_type=%s"}, 10924af4662fSMimi Zohar {Opt_subj_user, "subj_user=%s"}, 10934af4662fSMimi Zohar {Opt_subj_role, "subj_role=%s"}, 10944af4662fSMimi Zohar {Opt_subj_type, "subj_type=%s"}, 10954af4662fSMimi Zohar {Opt_func, "func=%s"}, 10964af4662fSMimi Zohar {Opt_mask, "mask=%s"}, 10974af4662fSMimi Zohar {Opt_fsmagic, "fsmagic=%s"}, 1098f1b08bbcSMimi Zohar {Opt_fsname, "fsname=%s"}, 109985865c1fSDmitry Kasatkin {Opt_fsuuid, "fsuuid=%s"}, 11003dd0c8d0SMikhail Kurinnoi {Opt_uid_eq, "uid=%s"}, 11013dd0c8d0SMikhail Kurinnoi {Opt_euid_eq, "euid=%s"}, 110240224c41SCurtis Veit {Opt_gid_eq, "gid=%s"}, 110340224c41SCurtis Veit {Opt_egid_eq, "egid=%s"}, 11043dd0c8d0SMikhail Kurinnoi {Opt_fowner_eq, "fowner=%s"}, 110540224c41SCurtis Veit {Opt_fgroup_eq, "fgroup=%s"}, 11063dd0c8d0SMikhail Kurinnoi {Opt_uid_gt, "uid>%s"}, 11073dd0c8d0SMikhail Kurinnoi {Opt_euid_gt, "euid>%s"}, 110840224c41SCurtis Veit {Opt_gid_gt, "gid>%s"}, 110940224c41SCurtis Veit {Opt_egid_gt, "egid>%s"}, 11103dd0c8d0SMikhail Kurinnoi {Opt_fowner_gt, "fowner>%s"}, 111140224c41SCurtis Veit {Opt_fgroup_gt, "fgroup>%s"}, 11123dd0c8d0SMikhail Kurinnoi {Opt_uid_lt, "uid<%s"}, 11133dd0c8d0SMikhail Kurinnoi {Opt_euid_lt, "euid<%s"}, 111440224c41SCurtis Veit {Opt_gid_lt, "gid<%s"}, 111540224c41SCurtis Veit {Opt_egid_lt, "egid<%s"}, 11163dd0c8d0SMikhail Kurinnoi {Opt_fowner_lt, "fowner<%s"}, 111740224c41SCurtis Veit {Opt_fgroup_lt, "fgroup<%s"}, 111854f03916SMimi Zohar {Opt_digest_type, "digest_type=%s"}, 11190e5a247cSDmitry Kasatkin {Opt_appraise_type, "appraise_type=%s"}, 1120273df864SNayna Jain {Opt_appraise_flag, "appraise_flag=%s"}, 1121583a80aeSTHOBY Simon {Opt_appraise_algos, "appraise_algos=%s"}, 1122f9b2a735SMimi Zohar {Opt_permit_directio, "permit_directio"}, 11230260643cSEric Richter {Opt_pcr, "pcr=%s"}, 112419453ce0SMatthew Garrett {Opt_template, "template=%s"}, 11252b60c0ecSLakshmi Ramasubramanian {Opt_keyrings, "keyrings=%s"}, 112647d76a48STushar Sugandhi {Opt_label, "label=%s"}, 11274af4662fSMimi Zohar {Opt_err, NULL} 11284af4662fSMimi Zohar }; 11294af4662fSMimi Zohar 113007f6a794SMimi Zohar static int ima_lsm_rule_init(struct ima_rule_entry *entry, 11317163a993SMimi Zohar substring_t *args, int lsm_rule, int audit_type) 11324af4662fSMimi Zohar { 11334af4662fSMimi Zohar int result; 11344af4662fSMimi Zohar 11357b62e162SEric Paris if (entry->lsm[lsm_rule].rule) 11367b62e162SEric Paris return -EINVAL; 11377b62e162SEric Paris 11387163a993SMimi Zohar entry->lsm[lsm_rule].args_p = match_strdup(args); 11397163a993SMimi Zohar if (!entry->lsm[lsm_rule].args_p) 11407163a993SMimi Zohar return -ENOMEM; 11417163a993SMimi Zohar 11424af4662fSMimi Zohar entry->lsm[lsm_rule].type = audit_type; 1143b8867eedSTyler Hicks result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal, 11447163a993SMimi Zohar entry->lsm[lsm_rule].args_p, 1145*9a95c5bfSGUO Zihua &entry->lsm[lsm_rule].rule, 1146*9a95c5bfSGUO Zihua GFP_KERNEL); 11477163a993SMimi Zohar if (!entry->lsm[lsm_rule].rule) { 1148483ec26eSJanne Karhunen pr_warn("rule for LSM \'%s\' is undefined\n", 1149aa0c0227STyler Hicks entry->lsm[lsm_rule].args_p); 1150483ec26eSJanne Karhunen 1151eb0782bbSliqiong if (ima_rules == (struct list_head __rcu *)(&ima_default_rules)) { 11527163a993SMimi Zohar kfree(entry->lsm[lsm_rule].args_p); 11532bdd737cSTyler Hicks entry->lsm[lsm_rule].args_p = NULL; 1154483ec26eSJanne Karhunen result = -EINVAL; 1155483ec26eSJanne Karhunen } else 1156483ec26eSJanne Karhunen result = 0; 11577163a993SMimi Zohar } 11587163a993SMimi Zohar 11594af4662fSMimi Zohar return result; 11604af4662fSMimi Zohar } 11614af4662fSMimi Zohar 11623dd0c8d0SMikhail Kurinnoi static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value, 116340224c41SCurtis Veit enum policy_opt rule_operator) 11642f1506cdSEric Paris { 11652afd020aSStefan Berger if (!ab) 11662afd020aSStefan Berger return; 11672afd020aSStefan Berger 116840224c41SCurtis Veit switch (rule_operator) { 116940224c41SCurtis Veit case Opt_uid_gt: 117040224c41SCurtis Veit case Opt_euid_gt: 117140224c41SCurtis Veit case Opt_gid_gt: 117240224c41SCurtis Veit case Opt_egid_gt: 117340224c41SCurtis Veit case Opt_fowner_gt: 117440224c41SCurtis Veit case Opt_fgroup_gt: 11753dd0c8d0SMikhail Kurinnoi audit_log_format(ab, "%s>", key); 117640224c41SCurtis Veit break; 117740224c41SCurtis Veit case Opt_uid_lt: 117840224c41SCurtis Veit case Opt_euid_lt: 117940224c41SCurtis Veit case Opt_gid_lt: 118040224c41SCurtis Veit case Opt_egid_lt: 118140224c41SCurtis Veit case Opt_fowner_lt: 118240224c41SCurtis Veit case Opt_fgroup_lt: 11833dd0c8d0SMikhail Kurinnoi audit_log_format(ab, "%s<", key); 118440224c41SCurtis Veit break; 118540224c41SCurtis Veit default: 11862f1506cdSEric Paris audit_log_format(ab, "%s=", key); 118740224c41SCurtis Veit } 11883d2859d5SStefan Berger audit_log_format(ab, "%s ", value); 11892f1506cdSEric Paris } 11903dd0c8d0SMikhail Kurinnoi static void ima_log_string(struct audit_buffer *ab, char *key, char *value) 11913dd0c8d0SMikhail Kurinnoi { 119240224c41SCurtis Veit ima_log_string_op(ab, key, value, Opt_err); 11933dd0c8d0SMikhail Kurinnoi } 11942f1506cdSEric Paris 11953878d505SThiago Jung Bauermann /* 11963878d505SThiago Jung Bauermann * Validating the appended signature included in the measurement list requires 11973878d505SThiago Jung Bauermann * the file hash calculated without the appended signature (i.e., the 'd-modsig' 11983878d505SThiago Jung Bauermann * field). Therefore, notify the user if they have the 'modsig' field but not 11993878d505SThiago Jung Bauermann * the 'd-modsig' field in the template. 12003878d505SThiago Jung Bauermann */ 12013878d505SThiago Jung Bauermann static void check_template_modsig(const struct ima_template_desc *template) 12023878d505SThiago Jung Bauermann { 12033878d505SThiago Jung Bauermann #define MSG "template with 'modsig' field also needs 'd-modsig' field\n" 12043878d505SThiago Jung Bauermann bool has_modsig, has_dmodsig; 12053878d505SThiago Jung Bauermann static bool checked; 12063878d505SThiago Jung Bauermann int i; 12073878d505SThiago Jung Bauermann 12083878d505SThiago Jung Bauermann /* We only need to notify the user once. */ 12093878d505SThiago Jung Bauermann if (checked) 12103878d505SThiago Jung Bauermann return; 12113878d505SThiago Jung Bauermann 12123878d505SThiago Jung Bauermann has_modsig = has_dmodsig = false; 12133878d505SThiago Jung Bauermann for (i = 0; i < template->num_fields; i++) { 12143878d505SThiago Jung Bauermann if (!strcmp(template->fields[i]->field_id, "modsig")) 12153878d505SThiago Jung Bauermann has_modsig = true; 12163878d505SThiago Jung Bauermann else if (!strcmp(template->fields[i]->field_id, "d-modsig")) 12173878d505SThiago Jung Bauermann has_dmodsig = true; 12183878d505SThiago Jung Bauermann } 12193878d505SThiago Jung Bauermann 12203878d505SThiago Jung Bauermann if (has_modsig && !has_dmodsig) 12213878d505SThiago Jung Bauermann pr_notice(MSG); 12223878d505SThiago Jung Bauermann 12233878d505SThiago Jung Bauermann checked = true; 12243878d505SThiago Jung Bauermann #undef MSG 12253878d505SThiago Jung Bauermann } 12263878d505SThiago Jung Bauermann 122754f03916SMimi Zohar /* 122854f03916SMimi Zohar * Warn if the template does not contain the given field. 122954f03916SMimi Zohar */ 123054f03916SMimi Zohar static void check_template_field(const struct ima_template_desc *template, 123154f03916SMimi Zohar const char *field, const char *msg) 123254f03916SMimi Zohar { 123354f03916SMimi Zohar int i; 123454f03916SMimi Zohar 123554f03916SMimi Zohar for (i = 0; i < template->num_fields; i++) 123654f03916SMimi Zohar if (!strcmp(template->fields[i]->field_id, field)) 123754f03916SMimi Zohar return; 123854f03916SMimi Zohar 123954f03916SMimi Zohar pr_notice_once("%s", msg); 124054f03916SMimi Zohar } 124154f03916SMimi Zohar 124271218343STyler Hicks static bool ima_validate_rule(struct ima_rule_entry *entry) 124371218343STyler Hicks { 124430031b0eSTyler Hicks /* Ensure that the action is set and is compatible with the flags */ 124571218343STyler Hicks if (entry->action == UNKNOWN) 124671218343STyler Hicks return false; 124771218343STyler Hicks 124830031b0eSTyler Hicks if (entry->action != MEASURE && entry->flags & IMA_PCR) 124930031b0eSTyler Hicks return false; 125030031b0eSTyler Hicks 125130031b0eSTyler Hicks if (entry->action != APPRAISE && 1252583a80aeSTHOBY Simon entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | 1253583a80aeSTHOBY Simon IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS)) 125430031b0eSTyler Hicks return false; 125530031b0eSTyler Hicks 125630031b0eSTyler Hicks /* 125730031b0eSTyler Hicks * The IMA_FUNC bit must be set if and only if there's a valid hook 125830031b0eSTyler Hicks * function specified, and vice versa. Enforcing this property allows 125930031b0eSTyler Hicks * for the NONE case below to validate a rule without an explicit hook 126030031b0eSTyler Hicks * function. 126130031b0eSTyler Hicks */ 126230031b0eSTyler Hicks if (((entry->flags & IMA_FUNC) && entry->func == NONE) || 126330031b0eSTyler Hicks (!(entry->flags & IMA_FUNC) && entry->func != NONE)) 126430031b0eSTyler Hicks return false; 126530031b0eSTyler Hicks 126671218343STyler Hicks /* 126771218343STyler Hicks * Ensure that the hook function is compatible with the other 126871218343STyler Hicks * components of the rule 126971218343STyler Hicks */ 127071218343STyler Hicks switch (entry->func) { 127171218343STyler Hicks case NONE: 127271218343STyler Hicks case FILE_CHECK: 127371218343STyler Hicks case MMAP_CHECK: 12744958db32SRoberto Sassu case MMAP_CHECK_REQPROT: 127571218343STyler Hicks case BPRM_CHECK: 127671218343STyler Hicks case CREDS_CHECK: 127771218343STyler Hicks case POST_SETATTR: 127871218343STyler Hicks case FIRMWARE_CHECK: 127930031b0eSTyler Hicks case POLICY_CHECK: 128030031b0eSTyler Hicks if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | 128130031b0eSTyler Hicks IMA_UID | IMA_FOWNER | IMA_FSUUID | 128230031b0eSTyler Hicks IMA_INMASK | IMA_EUID | IMA_PCR | 128340224c41SCurtis Veit IMA_FSNAME | IMA_GID | IMA_EGID | 128440224c41SCurtis Veit IMA_FGROUP | IMA_DIGSIG_REQUIRED | 128554f03916SMimi Zohar IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS | 1286f20765fdSEric Snowberg IMA_CHECK_BLACKLIST | IMA_VERITY_REQUIRED)) 128730031b0eSTyler Hicks return false; 128830031b0eSTyler Hicks 128930031b0eSTyler Hicks break; 129030031b0eSTyler Hicks case MODULE_CHECK: 129171218343STyler Hicks case KEXEC_KERNEL_CHECK: 129271218343STyler Hicks case KEXEC_INITRAMFS_CHECK: 129330031b0eSTyler Hicks if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | 129430031b0eSTyler Hicks IMA_UID | IMA_FOWNER | IMA_FSUUID | 129530031b0eSTyler Hicks IMA_INMASK | IMA_EUID | IMA_PCR | 129640224c41SCurtis Veit IMA_FSNAME | IMA_GID | IMA_EGID | 129740224c41SCurtis Veit IMA_FGROUP | IMA_DIGSIG_REQUIRED | 129830031b0eSTyler Hicks IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED | 1299583a80aeSTHOBY Simon IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS)) 130030031b0eSTyler Hicks return false; 130130031b0eSTyler Hicks 130271218343STyler Hicks break; 130371218343STyler Hicks case KEXEC_CMDLINE: 1304db2045f5STyler Hicks if (entry->action & ~(MEASURE | DONT_MEASURE)) 1305db2045f5STyler Hicks return false; 1306db2045f5STyler Hicks 13074834177eSTyler Hicks if (entry->flags & ~(IMA_FUNC | IMA_FSMAGIC | IMA_UID | 13084834177eSTyler Hicks IMA_FOWNER | IMA_FSUUID | IMA_EUID | 130940224c41SCurtis Veit IMA_PCR | IMA_FSNAME | IMA_GID | IMA_EGID | 131040224c41SCurtis Veit IMA_FGROUP)) 1311db2045f5STyler Hicks return false; 1312db2045f5STyler Hicks 1313db2045f5STyler Hicks break; 131471218343STyler Hicks case KEY_CHECK: 131571218343STyler Hicks if (entry->action & ~(MEASURE | DONT_MEASURE)) 131671218343STyler Hicks return false; 131771218343STyler Hicks 131840224c41SCurtis Veit if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR | 1319eb624fe2STyler Hicks IMA_KEYRINGS)) 1320eb624fe2STyler Hicks return false; 1321eb624fe2STyler Hicks 1322eb624fe2STyler Hicks if (ima_rule_contains_lsm_cond(entry)) 1323eb624fe2STyler Hicks return false; 1324eb624fe2STyler Hicks 132571218343STyler Hicks break; 1326c4e43aa2STushar Sugandhi case CRITICAL_DATA: 1327c4e43aa2STushar Sugandhi if (entry->action & ~(MEASURE | DONT_MEASURE)) 1328c4e43aa2STushar Sugandhi return false; 1329c4e43aa2STushar Sugandhi 133040224c41SCurtis Veit if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR | 133147d76a48STushar Sugandhi IMA_LABEL)) 1332c4e43aa2STushar Sugandhi return false; 1333c4e43aa2STushar Sugandhi 1334c4e43aa2STushar Sugandhi if (ima_rule_contains_lsm_cond(entry)) 1335c4e43aa2STushar Sugandhi return false; 1336c4e43aa2STushar Sugandhi 1337c4e43aa2STushar Sugandhi break; 13384f2946aaSTHOBY Simon case SETXATTR_CHECK: 13394f2946aaSTHOBY Simon /* any action other than APPRAISE is unsupported */ 13404f2946aaSTHOBY Simon if (entry->action != APPRAISE) 13414f2946aaSTHOBY Simon return false; 13424f2946aaSTHOBY Simon 13434f2946aaSTHOBY Simon /* SETXATTR_CHECK requires an appraise_algos parameter */ 13444f2946aaSTHOBY Simon if (!(entry->flags & IMA_VALIDATE_ALGOS)) 13454f2946aaSTHOBY Simon return false; 13464f2946aaSTHOBY Simon 13474f2946aaSTHOBY Simon /* 13484f2946aaSTHOBY Simon * full policies are not supported, they would have too 13494f2946aaSTHOBY Simon * much of a performance impact 13504f2946aaSTHOBY Simon */ 13514f2946aaSTHOBY Simon if (entry->flags & ~(IMA_FUNC | IMA_VALIDATE_ALGOS)) 13524f2946aaSTHOBY Simon return false; 13534f2946aaSTHOBY Simon 13544f2946aaSTHOBY Simon break; 135571218343STyler Hicks default: 135671218343STyler Hicks return false; 135771218343STyler Hicks } 135871218343STyler Hicks 13595f3e9265STyler Hicks /* Ensure that combinations of flags are compatible with each other */ 13605f3e9265STyler Hicks if (entry->flags & IMA_CHECK_BLACKLIST && 1361f20765fdSEric Snowberg !(entry->flags & IMA_DIGSIG_REQUIRED)) 13625f3e9265STyler Hicks return false; 13635f3e9265STyler Hicks 1364398c42e2SMimi Zohar /* 1365398c42e2SMimi Zohar * Unlike for regular IMA 'appraise' policy rules where security.ima 1366398c42e2SMimi Zohar * xattr may contain either a file hash or signature, the security.ima 1367398c42e2SMimi Zohar * xattr for fsverity must contain a file signature (sigv3). Ensure 1368398c42e2SMimi Zohar * that 'appraise' rules for fsverity require file signatures by 1369398c42e2SMimi Zohar * checking the IMA_DIGSIG_REQUIRED flag is set. 1370398c42e2SMimi Zohar */ 1371398c42e2SMimi Zohar if (entry->action == APPRAISE && 1372398c42e2SMimi Zohar (entry->flags & IMA_VERITY_REQUIRED) && 1373398c42e2SMimi Zohar !(entry->flags & IMA_DIGSIG_REQUIRED)) 1374398c42e2SMimi Zohar return false; 1375398c42e2SMimi Zohar 137671218343STyler Hicks return true; 137771218343STyler Hicks } 137871218343STyler Hicks 1379583a80aeSTHOBY Simon static unsigned int ima_parse_appraise_algos(char *arg) 1380583a80aeSTHOBY Simon { 1381583a80aeSTHOBY Simon unsigned int res = 0; 1382583a80aeSTHOBY Simon int idx; 1383583a80aeSTHOBY Simon char *token; 1384583a80aeSTHOBY Simon 1385583a80aeSTHOBY Simon while ((token = strsep(&arg, ",")) != NULL) { 1386583a80aeSTHOBY Simon idx = match_string(hash_algo_name, HASH_ALGO__LAST, token); 1387583a80aeSTHOBY Simon 1388583a80aeSTHOBY Simon if (idx < 0) { 1389583a80aeSTHOBY Simon pr_err("unknown hash algorithm \"%s\"", 1390583a80aeSTHOBY Simon token); 1391583a80aeSTHOBY Simon return 0; 1392583a80aeSTHOBY Simon } 1393583a80aeSTHOBY Simon 13948ecd39cbSTHOBY Simon if (!crypto_has_alg(hash_algo_name[idx], 0, 0)) { 13958ecd39cbSTHOBY Simon pr_err("unavailable hash algorithm \"%s\", check your kernel configuration", 13968ecd39cbSTHOBY Simon token); 13978ecd39cbSTHOBY Simon return 0; 13988ecd39cbSTHOBY Simon } 13998ecd39cbSTHOBY Simon 1400583a80aeSTHOBY Simon /* Add the hash algorithm to the 'allowed' bitfield */ 1401583a80aeSTHOBY Simon res |= (1U << idx); 1402583a80aeSTHOBY Simon } 1403583a80aeSTHOBY Simon 1404583a80aeSTHOBY Simon return res; 1405583a80aeSTHOBY Simon } 1406583a80aeSTHOBY Simon 140707f6a794SMimi Zohar static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) 14084af4662fSMimi Zohar { 14094af4662fSMimi Zohar struct audit_buffer *ab; 14104351c294SMimi Zohar char *from; 14114af4662fSMimi Zohar char *p; 141240224c41SCurtis Veit bool eid_token; /* either euid or egid */ 141319453ce0SMatthew Garrett struct ima_template_desc *template_desc; 14144af4662fSMimi Zohar int result = 0; 14154af4662fSMimi Zohar 1416dba31ee7SStefan Berger ab = integrity_audit_log_start(audit_context(), GFP_KERNEL, 1417dba31ee7SStefan Berger AUDIT_INTEGRITY_POLICY_RULE); 14184af4662fSMimi Zohar 14198b94eea4SEric W. Biederman entry->uid = INVALID_UID; 142040224c41SCurtis Veit entry->gid = INVALID_GID; 142188265322SLinus Torvalds entry->fowner = INVALID_UID; 142240224c41SCurtis Veit entry->fgroup = INVALID_GID; 14233dd0c8d0SMikhail Kurinnoi entry->uid_op = &uid_eq; 142440224c41SCurtis Veit entry->gid_op = &gid_eq; 14258e27a7aeSChristian Brauner entry->fowner_op = &vfsuid_eq_kuid; 14268e27a7aeSChristian Brauner entry->fgroup_op = &vfsgid_eq_kgid; 1427b9035b1fSEric Paris entry->action = UNKNOWN; 142828ef4002SEric Paris while ((p = strsep(&rule, " \t")) != NULL) { 14294af4662fSMimi Zohar substring_t args[MAX_OPT_ARGS]; 14304af4662fSMimi Zohar int token; 14314af4662fSMimi Zohar unsigned long lnum; 14324af4662fSMimi Zohar 14334af4662fSMimi Zohar if (result < 0) 14344af4662fSMimi Zohar break; 143528ef4002SEric Paris if ((*p == '\0') || (*p == ' ') || (*p == '\t')) 143628ef4002SEric Paris continue; 14374af4662fSMimi Zohar token = match_token(p, policy_tokens, args); 14384af4662fSMimi Zohar switch (token) { 14394af4662fSMimi Zohar case Opt_measure: 14402f1506cdSEric Paris ima_log_string(ab, "action", "measure"); 14417b62e162SEric Paris 14427b62e162SEric Paris if (entry->action != UNKNOWN) 14437b62e162SEric Paris result = -EINVAL; 14447b62e162SEric Paris 14454af4662fSMimi Zohar entry->action = MEASURE; 14464af4662fSMimi Zohar break; 14474af4662fSMimi Zohar case Opt_dont_measure: 14482f1506cdSEric Paris ima_log_string(ab, "action", "dont_measure"); 14497b62e162SEric Paris 14507b62e162SEric Paris if (entry->action != UNKNOWN) 14517b62e162SEric Paris result = -EINVAL; 14527b62e162SEric Paris 14534af4662fSMimi Zohar entry->action = DONT_MEASURE; 14544af4662fSMimi Zohar break; 145507f6a794SMimi Zohar case Opt_appraise: 145607f6a794SMimi Zohar ima_log_string(ab, "action", "appraise"); 145707f6a794SMimi Zohar 145807f6a794SMimi Zohar if (entry->action != UNKNOWN) 145907f6a794SMimi Zohar result = -EINVAL; 146007f6a794SMimi Zohar 146107f6a794SMimi Zohar entry->action = APPRAISE; 146207f6a794SMimi Zohar break; 146307f6a794SMimi Zohar case Opt_dont_appraise: 146407f6a794SMimi Zohar ima_log_string(ab, "action", "dont_appraise"); 146507f6a794SMimi Zohar 146607f6a794SMimi Zohar if (entry->action != UNKNOWN) 146707f6a794SMimi Zohar result = -EINVAL; 146807f6a794SMimi Zohar 146907f6a794SMimi Zohar entry->action = DONT_APPRAISE; 147007f6a794SMimi Zohar break; 1471e7c568e0SPeter Moody case Opt_audit: 1472e7c568e0SPeter Moody ima_log_string(ab, "action", "audit"); 1473e7c568e0SPeter Moody 1474e7c568e0SPeter Moody if (entry->action != UNKNOWN) 1475e7c568e0SPeter Moody result = -EINVAL; 1476e7c568e0SPeter Moody 1477e7c568e0SPeter Moody entry->action = AUDIT; 1478e7c568e0SPeter Moody break; 1479da1b0029SMimi Zohar case Opt_hash: 1480da1b0029SMimi Zohar ima_log_string(ab, "action", "hash"); 1481da1b0029SMimi Zohar 1482da1b0029SMimi Zohar if (entry->action != UNKNOWN) 1483da1b0029SMimi Zohar result = -EINVAL; 1484da1b0029SMimi Zohar 1485da1b0029SMimi Zohar entry->action = HASH; 1486da1b0029SMimi Zohar break; 1487da1b0029SMimi Zohar case Opt_dont_hash: 1488da1b0029SMimi Zohar ima_log_string(ab, "action", "dont_hash"); 1489da1b0029SMimi Zohar 1490da1b0029SMimi Zohar if (entry->action != UNKNOWN) 1491da1b0029SMimi Zohar result = -EINVAL; 1492da1b0029SMimi Zohar 1493da1b0029SMimi Zohar entry->action = DONT_HASH; 1494da1b0029SMimi Zohar break; 14954af4662fSMimi Zohar case Opt_func: 14962f1506cdSEric Paris ima_log_string(ab, "func", args[0].from); 14977b62e162SEric Paris 14987b62e162SEric Paris if (entry->func) 14997b62e162SEric Paris result = -EINVAL; 15007b62e162SEric Paris 15011e93d005SMimi Zohar if (strcmp(args[0].from, "FILE_CHECK") == 0) 15021e93d005SMimi Zohar entry->func = FILE_CHECK; 15031e93d005SMimi Zohar /* PATH_CHECK is for backwards compat */ 15041e93d005SMimi Zohar else if (strcmp(args[0].from, "PATH_CHECK") == 0) 15051e93d005SMimi Zohar entry->func = FILE_CHECK; 1506fdf90729SMimi Zohar else if (strcmp(args[0].from, "MODULE_CHECK") == 0) 1507fdf90729SMimi Zohar entry->func = MODULE_CHECK; 15085a9196d7SMimi Zohar else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0) 15095a9196d7SMimi Zohar entry->func = FIRMWARE_CHECK; 151016cac49fSMimi Zohar else if ((strcmp(args[0].from, "FILE_MMAP") == 0) 151116cac49fSMimi Zohar || (strcmp(args[0].from, "MMAP_CHECK") == 0)) 151216cac49fSMimi Zohar entry->func = MMAP_CHECK; 15134958db32SRoberto Sassu else if ((strcmp(args[0].from, "MMAP_CHECK_REQPROT") == 0)) 15144958db32SRoberto Sassu entry->func = MMAP_CHECK_REQPROT; 15154af4662fSMimi Zohar else if (strcmp(args[0].from, "BPRM_CHECK") == 0) 15164af4662fSMimi Zohar entry->func = BPRM_CHECK; 1517d906c10dSMatthew Garrett else if (strcmp(args[0].from, "CREDS_CHECK") == 0) 1518d906c10dSMatthew Garrett entry->func = CREDS_CHECK; 1519d9ddf077SMimi Zohar else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") == 1520d9ddf077SMimi Zohar 0) 1521d9ddf077SMimi Zohar entry->func = KEXEC_KERNEL_CHECK; 1522d9ddf077SMimi Zohar else if (strcmp(args[0].from, "KEXEC_INITRAMFS_CHECK") 1523d9ddf077SMimi Zohar == 0) 1524d9ddf077SMimi Zohar entry->func = KEXEC_INITRAMFS_CHECK; 152519f8a847SMimi Zohar else if (strcmp(args[0].from, "POLICY_CHECK") == 0) 152619f8a847SMimi Zohar entry->func = POLICY_CHECK; 1527b0935123SPrakhar Srivastava else if (strcmp(args[0].from, "KEXEC_CMDLINE") == 0) 1528b0935123SPrakhar Srivastava entry->func = KEXEC_CMDLINE; 152948ce1ddcSTyler Hicks else if (IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) && 153048ce1ddcSTyler Hicks strcmp(args[0].from, "KEY_CHECK") == 0) 15315808611cSLakshmi Ramasubramanian entry->func = KEY_CHECK; 1532c4e43aa2STushar Sugandhi else if (strcmp(args[0].from, "CRITICAL_DATA") == 0) 1533c4e43aa2STushar Sugandhi entry->func = CRITICAL_DATA; 15344f2946aaSTHOBY Simon else if (strcmp(args[0].from, "SETXATTR_CHECK") == 0) 15354f2946aaSTHOBY Simon entry->func = SETXATTR_CHECK; 15364af4662fSMimi Zohar else 15374af4662fSMimi Zohar result = -EINVAL; 15384af4662fSMimi Zohar if (!result) 15394af4662fSMimi Zohar entry->flags |= IMA_FUNC; 15404af4662fSMimi Zohar break; 15414af4662fSMimi Zohar case Opt_mask: 15422f1506cdSEric Paris ima_log_string(ab, "mask", args[0].from); 15437b62e162SEric Paris 15447b62e162SEric Paris if (entry->mask) 15457b62e162SEric Paris result = -EINVAL; 15467b62e162SEric Paris 15474351c294SMimi Zohar from = args[0].from; 15484351c294SMimi Zohar if (*from == '^') 15494351c294SMimi Zohar from++; 15504351c294SMimi Zohar 15514351c294SMimi Zohar if ((strcmp(from, "MAY_EXEC")) == 0) 15524af4662fSMimi Zohar entry->mask = MAY_EXEC; 15534351c294SMimi Zohar else if (strcmp(from, "MAY_WRITE") == 0) 15544af4662fSMimi Zohar entry->mask = MAY_WRITE; 15554351c294SMimi Zohar else if (strcmp(from, "MAY_READ") == 0) 15564af4662fSMimi Zohar entry->mask = MAY_READ; 15574351c294SMimi Zohar else if (strcmp(from, "MAY_APPEND") == 0) 15584af4662fSMimi Zohar entry->mask = MAY_APPEND; 15594af4662fSMimi Zohar else 15604af4662fSMimi Zohar result = -EINVAL; 15614af4662fSMimi Zohar if (!result) 15624351c294SMimi Zohar entry->flags |= (*args[0].from == '^') 15634351c294SMimi Zohar ? IMA_INMASK : IMA_MASK; 15644af4662fSMimi Zohar break; 15654af4662fSMimi Zohar case Opt_fsmagic: 15662f1506cdSEric Paris ima_log_string(ab, "fsmagic", args[0].from); 15677b62e162SEric Paris 15687b62e162SEric Paris if (entry->fsmagic) { 15697b62e162SEric Paris result = -EINVAL; 15707b62e162SEric Paris break; 15717b62e162SEric Paris } 15727b62e162SEric Paris 15732bb930abSDmitry Kasatkin result = kstrtoul(args[0].from, 16, &entry->fsmagic); 15744af4662fSMimi Zohar if (!result) 15754af4662fSMimi Zohar entry->flags |= IMA_FSMAGIC; 15764af4662fSMimi Zohar break; 1577f1b08bbcSMimi Zohar case Opt_fsname: 1578f1b08bbcSMimi Zohar ima_log_string(ab, "fsname", args[0].from); 1579f1b08bbcSMimi Zohar 1580f1b08bbcSMimi Zohar entry->fsname = kstrdup(args[0].from, GFP_KERNEL); 1581f1b08bbcSMimi Zohar if (!entry->fsname) { 1582f1b08bbcSMimi Zohar result = -ENOMEM; 1583f1b08bbcSMimi Zohar break; 1584f1b08bbcSMimi Zohar } 1585f1b08bbcSMimi Zohar result = 0; 1586f1b08bbcSMimi Zohar entry->flags |= IMA_FSNAME; 1587f1b08bbcSMimi Zohar break; 15882b60c0ecSLakshmi Ramasubramanian case Opt_keyrings: 15892b60c0ecSLakshmi Ramasubramanian ima_log_string(ab, "keyrings", args[0].from); 15902b60c0ecSLakshmi Ramasubramanian 159148ce1ddcSTyler Hicks if (!IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) || 159248ce1ddcSTyler Hicks entry->keyrings) { 15932b60c0ecSLakshmi Ramasubramanian result = -EINVAL; 15942b60c0ecSLakshmi Ramasubramanian break; 15952b60c0ecSLakshmi Ramasubramanian } 15965c7bac9fSLakshmi Ramasubramanian 1597176377d9STyler Hicks entry->keyrings = ima_alloc_rule_opt_list(args); 1598176377d9STyler Hicks if (IS_ERR(entry->keyrings)) { 1599176377d9STyler Hicks result = PTR_ERR(entry->keyrings); 1600176377d9STyler Hicks entry->keyrings = NULL; 16015c7bac9fSLakshmi Ramasubramanian break; 16025c7bac9fSLakshmi Ramasubramanian } 16035c7bac9fSLakshmi Ramasubramanian 16042b60c0ecSLakshmi Ramasubramanian entry->flags |= IMA_KEYRINGS; 16052b60c0ecSLakshmi Ramasubramanian break; 160647d76a48STushar Sugandhi case Opt_label: 160747d76a48STushar Sugandhi ima_log_string(ab, "label", args[0].from); 160847d76a48STushar Sugandhi 160947d76a48STushar Sugandhi if (entry->label) { 161047d76a48STushar Sugandhi result = -EINVAL; 161147d76a48STushar Sugandhi break; 161247d76a48STushar Sugandhi } 161347d76a48STushar Sugandhi 161447d76a48STushar Sugandhi entry->label = ima_alloc_rule_opt_list(args); 161547d76a48STushar Sugandhi if (IS_ERR(entry->label)) { 161647d76a48STushar Sugandhi result = PTR_ERR(entry->label); 161747d76a48STushar Sugandhi entry->label = NULL; 161847d76a48STushar Sugandhi break; 161947d76a48STushar Sugandhi } 162047d76a48STushar Sugandhi 162147d76a48STushar Sugandhi entry->flags |= IMA_LABEL; 162247d76a48STushar Sugandhi break; 162385865c1fSDmitry Kasatkin case Opt_fsuuid: 162485865c1fSDmitry Kasatkin ima_log_string(ab, "fsuuid", args[0].from); 162585865c1fSDmitry Kasatkin 162636447456SMike Rapoport if (!uuid_is_null(&entry->fsuuid)) { 162785865c1fSDmitry Kasatkin result = -EINVAL; 162885865c1fSDmitry Kasatkin break; 162985865c1fSDmitry Kasatkin } 163085865c1fSDmitry Kasatkin 1631787d8c53SChristoph Hellwig result = uuid_parse(args[0].from, &entry->fsuuid); 1632446d64e3SMimi Zohar if (!result) 163385865c1fSDmitry Kasatkin entry->flags |= IMA_FSUUID; 163485865c1fSDmitry Kasatkin break; 16353dd0c8d0SMikhail Kurinnoi case Opt_uid_gt: 16363dd0c8d0SMikhail Kurinnoi case Opt_euid_gt: 16373dd0c8d0SMikhail Kurinnoi entry->uid_op = &uid_gt; 1638df561f66SGustavo A. R. Silva fallthrough; 16393dd0c8d0SMikhail Kurinnoi case Opt_uid_lt: 16403dd0c8d0SMikhail Kurinnoi case Opt_euid_lt: 16413dd0c8d0SMikhail Kurinnoi if ((token == Opt_uid_lt) || (token == Opt_euid_lt)) 16423dd0c8d0SMikhail Kurinnoi entry->uid_op = &uid_lt; 1643df561f66SGustavo A. R. Silva fallthrough; 16443dd0c8d0SMikhail Kurinnoi case Opt_uid_eq: 16453dd0c8d0SMikhail Kurinnoi case Opt_euid_eq: 164640224c41SCurtis Veit eid_token = (token == Opt_euid_eq) || 164740224c41SCurtis Veit (token == Opt_euid_gt) || 164840224c41SCurtis Veit (token == Opt_euid_lt); 16493dd0c8d0SMikhail Kurinnoi 165040224c41SCurtis Veit ima_log_string_op(ab, eid_token ? "euid" : "uid", 165140224c41SCurtis Veit args[0].from, token); 16527b62e162SEric Paris 16538b94eea4SEric W. Biederman if (uid_valid(entry->uid)) { 16547b62e162SEric Paris result = -EINVAL; 16557b62e162SEric Paris break; 16567b62e162SEric Paris } 16577b62e162SEric Paris 165829707b20SJingoo Han result = kstrtoul(args[0].from, 10, &lnum); 16594af4662fSMimi Zohar if (!result) { 1660139069efSMimi Zohar entry->uid = make_kuid(current_user_ns(), 1661139069efSMimi Zohar (uid_t) lnum); 1662139069efSMimi Zohar if (!uid_valid(entry->uid) || 1663139069efSMimi Zohar (uid_t)lnum != lnum) 16644af4662fSMimi Zohar result = -EINVAL; 16654af4662fSMimi Zohar else 166640224c41SCurtis Veit entry->flags |= eid_token 166740224c41SCurtis Veit ? IMA_EUID : IMA_UID; 166840224c41SCurtis Veit } 166940224c41SCurtis Veit break; 167040224c41SCurtis Veit case Opt_gid_gt: 167140224c41SCurtis Veit case Opt_egid_gt: 167240224c41SCurtis Veit entry->gid_op = &gid_gt; 167340224c41SCurtis Veit fallthrough; 167440224c41SCurtis Veit case Opt_gid_lt: 167540224c41SCurtis Veit case Opt_egid_lt: 167640224c41SCurtis Veit if ((token == Opt_gid_lt) || (token == Opt_egid_lt)) 167740224c41SCurtis Veit entry->gid_op = &gid_lt; 167840224c41SCurtis Veit fallthrough; 167940224c41SCurtis Veit case Opt_gid_eq: 168040224c41SCurtis Veit case Opt_egid_eq: 168140224c41SCurtis Veit eid_token = (token == Opt_egid_eq) || 168240224c41SCurtis Veit (token == Opt_egid_gt) || 168340224c41SCurtis Veit (token == Opt_egid_lt); 168440224c41SCurtis Veit 168540224c41SCurtis Veit ima_log_string_op(ab, eid_token ? "egid" : "gid", 168640224c41SCurtis Veit args[0].from, token); 168740224c41SCurtis Veit 168840224c41SCurtis Veit if (gid_valid(entry->gid)) { 168940224c41SCurtis Veit result = -EINVAL; 169040224c41SCurtis Veit break; 169140224c41SCurtis Veit } 169240224c41SCurtis Veit 169340224c41SCurtis Veit result = kstrtoul(args[0].from, 10, &lnum); 169440224c41SCurtis Veit if (!result) { 169540224c41SCurtis Veit entry->gid = make_kgid(current_user_ns(), 169640224c41SCurtis Veit (gid_t)lnum); 169740224c41SCurtis Veit if (!gid_valid(entry->gid) || 169840224c41SCurtis Veit (((gid_t)lnum) != lnum)) 169940224c41SCurtis Veit result = -EINVAL; 170040224c41SCurtis Veit else 170140224c41SCurtis Veit entry->flags |= eid_token 170240224c41SCurtis Veit ? IMA_EGID : IMA_GID; 17034af4662fSMimi Zohar } 17044af4662fSMimi Zohar break; 17053dd0c8d0SMikhail Kurinnoi case Opt_fowner_gt: 17068e27a7aeSChristian Brauner entry->fowner_op = &vfsuid_gt_kuid; 1707df561f66SGustavo A. R. Silva fallthrough; 17083dd0c8d0SMikhail Kurinnoi case Opt_fowner_lt: 17093dd0c8d0SMikhail Kurinnoi if (token == Opt_fowner_lt) 17108e27a7aeSChristian Brauner entry->fowner_op = &vfsuid_lt_kuid; 1711df561f66SGustavo A. R. Silva fallthrough; 17123dd0c8d0SMikhail Kurinnoi case Opt_fowner_eq: 171340224c41SCurtis Veit ima_log_string_op(ab, "fowner", args[0].from, token); 171407f6a794SMimi Zohar 171588265322SLinus Torvalds if (uid_valid(entry->fowner)) { 171607f6a794SMimi Zohar result = -EINVAL; 171707f6a794SMimi Zohar break; 171807f6a794SMimi Zohar } 171907f6a794SMimi Zohar 172029707b20SJingoo Han result = kstrtoul(args[0].from, 10, &lnum); 172107f6a794SMimi Zohar if (!result) { 172230d8764aSAlex Henrie entry->fowner = make_kuid(current_user_ns(), 172330d8764aSAlex Henrie (uid_t)lnum); 172430d8764aSAlex Henrie if (!uid_valid(entry->fowner) || 172530d8764aSAlex Henrie (((uid_t)lnum) != lnum)) 172607f6a794SMimi Zohar result = -EINVAL; 172707f6a794SMimi Zohar else 172807f6a794SMimi Zohar entry->flags |= IMA_FOWNER; 172907f6a794SMimi Zohar } 173007f6a794SMimi Zohar break; 173140224c41SCurtis Veit case Opt_fgroup_gt: 17328e27a7aeSChristian Brauner entry->fgroup_op = &vfsgid_gt_kgid; 173340224c41SCurtis Veit fallthrough; 173440224c41SCurtis Veit case Opt_fgroup_lt: 173540224c41SCurtis Veit if (token == Opt_fgroup_lt) 17368e27a7aeSChristian Brauner entry->fgroup_op = &vfsgid_lt_kgid; 173740224c41SCurtis Veit fallthrough; 173840224c41SCurtis Veit case Opt_fgroup_eq: 173940224c41SCurtis Veit ima_log_string_op(ab, "fgroup", args[0].from, token); 174040224c41SCurtis Veit 174140224c41SCurtis Veit if (gid_valid(entry->fgroup)) { 174240224c41SCurtis Veit result = -EINVAL; 174340224c41SCurtis Veit break; 174440224c41SCurtis Veit } 174540224c41SCurtis Veit 174640224c41SCurtis Veit result = kstrtoul(args[0].from, 10, &lnum); 174740224c41SCurtis Veit if (!result) { 174840224c41SCurtis Veit entry->fgroup = make_kgid(current_user_ns(), 174940224c41SCurtis Veit (gid_t)lnum); 175040224c41SCurtis Veit if (!gid_valid(entry->fgroup) || 175140224c41SCurtis Veit (((gid_t)lnum) != lnum)) 175240224c41SCurtis Veit result = -EINVAL; 175340224c41SCurtis Veit else 175440224c41SCurtis Veit entry->flags |= IMA_FGROUP; 175540224c41SCurtis Veit } 175640224c41SCurtis Veit break; 17574af4662fSMimi Zohar case Opt_obj_user: 17582f1506cdSEric Paris ima_log_string(ab, "obj_user", args[0].from); 17597163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17604af4662fSMimi Zohar LSM_OBJ_USER, 17614af4662fSMimi Zohar AUDIT_OBJ_USER); 17624af4662fSMimi Zohar break; 17634af4662fSMimi Zohar case Opt_obj_role: 17642f1506cdSEric Paris ima_log_string(ab, "obj_role", args[0].from); 17657163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17664af4662fSMimi Zohar LSM_OBJ_ROLE, 17674af4662fSMimi Zohar AUDIT_OBJ_ROLE); 17684af4662fSMimi Zohar break; 17694af4662fSMimi Zohar case Opt_obj_type: 17702f1506cdSEric Paris ima_log_string(ab, "obj_type", args[0].from); 17717163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17724af4662fSMimi Zohar LSM_OBJ_TYPE, 17734af4662fSMimi Zohar AUDIT_OBJ_TYPE); 17744af4662fSMimi Zohar break; 17754af4662fSMimi Zohar case Opt_subj_user: 17762f1506cdSEric Paris ima_log_string(ab, "subj_user", args[0].from); 17777163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17784af4662fSMimi Zohar LSM_SUBJ_USER, 17794af4662fSMimi Zohar AUDIT_SUBJ_USER); 17804af4662fSMimi Zohar break; 17814af4662fSMimi Zohar case Opt_subj_role: 17822f1506cdSEric Paris ima_log_string(ab, "subj_role", args[0].from); 17837163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17844af4662fSMimi Zohar LSM_SUBJ_ROLE, 17854af4662fSMimi Zohar AUDIT_SUBJ_ROLE); 17864af4662fSMimi Zohar break; 17874af4662fSMimi Zohar case Opt_subj_type: 17882f1506cdSEric Paris ima_log_string(ab, "subj_type", args[0].from); 17897163a993SMimi Zohar result = ima_lsm_rule_init(entry, args, 17904af4662fSMimi Zohar LSM_SUBJ_TYPE, 17914af4662fSMimi Zohar AUDIT_SUBJ_TYPE); 17924af4662fSMimi Zohar break; 179354f03916SMimi Zohar case Opt_digest_type: 179454f03916SMimi Zohar ima_log_string(ab, "digest_type", args[0].from); 1795398c42e2SMimi Zohar if (entry->flags & IMA_DIGSIG_REQUIRED) 1796398c42e2SMimi Zohar result = -EINVAL; 1797398c42e2SMimi Zohar else if ((strcmp(args[0].from, "verity")) == 0) 179854f03916SMimi Zohar entry->flags |= IMA_VERITY_REQUIRED; 179954f03916SMimi Zohar else 180054f03916SMimi Zohar result = -EINVAL; 180154f03916SMimi Zohar break; 18020e5a247cSDmitry Kasatkin case Opt_appraise_type: 18030e5a247cSDmitry Kasatkin ima_log_string(ab, "appraise_type", args[0].from); 1804398c42e2SMimi Zohar 1805398c42e2SMimi Zohar if ((strcmp(args[0].from, "imasig")) == 0) { 1806398c42e2SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 1807398c42e2SMimi Zohar result = -EINVAL; 1808398c42e2SMimi Zohar else 1809f20765fdSEric Snowberg entry->flags |= IMA_DIGSIG_REQUIRED | IMA_CHECK_BLACKLIST; 1810398c42e2SMimi Zohar } else if (strcmp(args[0].from, "sigv3") == 0) { 1811398c42e2SMimi Zohar /* Only fsverity supports sigv3 for now */ 1812398c42e2SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 1813f20765fdSEric Snowberg entry->flags |= IMA_DIGSIG_REQUIRED | IMA_CHECK_BLACKLIST; 18140e5a247cSDmitry Kasatkin else 18150e5a247cSDmitry Kasatkin result = -EINVAL; 1816398c42e2SMimi Zohar } else if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) && 1817398c42e2SMimi Zohar strcmp(args[0].from, "imasig|modsig") == 0) { 1818398c42e2SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 1819398c42e2SMimi Zohar result = -EINVAL; 1820398c42e2SMimi Zohar else 1821398c42e2SMimi Zohar entry->flags |= IMA_DIGSIG_REQUIRED | 1822f20765fdSEric Snowberg IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST; 1823398c42e2SMimi Zohar } else { 1824398c42e2SMimi Zohar result = -EINVAL; 1825398c42e2SMimi Zohar } 18260e5a247cSDmitry Kasatkin break; 1827273df864SNayna Jain case Opt_appraise_flag: 1828273df864SNayna Jain ima_log_string(ab, "appraise_flag", args[0].from); 1829273df864SNayna Jain break; 1830583a80aeSTHOBY Simon case Opt_appraise_algos: 1831583a80aeSTHOBY Simon ima_log_string(ab, "appraise_algos", args[0].from); 1832583a80aeSTHOBY Simon 1833583a80aeSTHOBY Simon if (entry->allowed_algos) { 1834583a80aeSTHOBY Simon result = -EINVAL; 1835583a80aeSTHOBY Simon break; 1836583a80aeSTHOBY Simon } 1837583a80aeSTHOBY Simon 1838583a80aeSTHOBY Simon entry->allowed_algos = 1839583a80aeSTHOBY Simon ima_parse_appraise_algos(args[0].from); 1840583a80aeSTHOBY Simon /* invalid or empty list of algorithms */ 1841583a80aeSTHOBY Simon if (!entry->allowed_algos) { 1842583a80aeSTHOBY Simon result = -EINVAL; 1843583a80aeSTHOBY Simon break; 1844583a80aeSTHOBY Simon } 1845583a80aeSTHOBY Simon 1846583a80aeSTHOBY Simon entry->flags |= IMA_VALIDATE_ALGOS; 1847583a80aeSTHOBY Simon 1848583a80aeSTHOBY Simon break; 1849f9b2a735SMimi Zohar case Opt_permit_directio: 1850f9b2a735SMimi Zohar entry->flags |= IMA_PERMIT_DIRECTIO; 1851f9b2a735SMimi Zohar break; 18520260643cSEric Richter case Opt_pcr: 18530260643cSEric Richter ima_log_string(ab, "pcr", args[0].from); 18540260643cSEric Richter 18550260643cSEric Richter result = kstrtoint(args[0].from, 10, &entry->pcr); 18560260643cSEric Richter if (result || INVALID_PCR(entry->pcr)) 18570260643cSEric Richter result = -EINVAL; 18580260643cSEric Richter else 18590260643cSEric Richter entry->flags |= IMA_PCR; 18600260643cSEric Richter 18610260643cSEric Richter break; 186219453ce0SMatthew Garrett case Opt_template: 186319453ce0SMatthew Garrett ima_log_string(ab, "template", args[0].from); 186419453ce0SMatthew Garrett if (entry->action != MEASURE) { 186519453ce0SMatthew Garrett result = -EINVAL; 186619453ce0SMatthew Garrett break; 186719453ce0SMatthew Garrett } 186819453ce0SMatthew Garrett template_desc = lookup_template_desc(args[0].from); 186919453ce0SMatthew Garrett if (!template_desc || entry->template) { 187019453ce0SMatthew Garrett result = -EINVAL; 187119453ce0SMatthew Garrett break; 187219453ce0SMatthew Garrett } 187319453ce0SMatthew Garrett 187419453ce0SMatthew Garrett /* 187519453ce0SMatthew Garrett * template_desc_init_fields() does nothing if 187619453ce0SMatthew Garrett * the template is already initialised, so 187719453ce0SMatthew Garrett * it's safe to do this unconditionally 187819453ce0SMatthew Garrett */ 187919453ce0SMatthew Garrett template_desc_init_fields(template_desc->fmt, 188019453ce0SMatthew Garrett &(template_desc->fields), 188119453ce0SMatthew Garrett &(template_desc->num_fields)); 188219453ce0SMatthew Garrett entry->template = template_desc; 188319453ce0SMatthew Garrett break; 18844af4662fSMimi Zohar case Opt_err: 18852f1506cdSEric Paris ima_log_string(ab, "UNKNOWN", p); 1886e9d393bfSEric Paris result = -EINVAL; 18874af4662fSMimi Zohar break; 18884af4662fSMimi Zohar } 18894af4662fSMimi Zohar } 189071218343STyler Hicks if (!result && !ima_validate_rule(entry)) 18914af4662fSMimi Zohar result = -EINVAL; 18926f0911a6SMimi Zohar else if (entry->action == APPRAISE) 18936f0911a6SMimi Zohar temp_ima_appraise |= ima_appraise_flag(entry->func); 18946f0911a6SMimi Zohar 18953878d505SThiago Jung Bauermann if (!result && entry->flags & IMA_MODSIG_ALLOWED) { 18963878d505SThiago Jung Bauermann template_desc = entry->template ? entry->template : 18973878d505SThiago Jung Bauermann ima_template_desc_current(); 18983878d505SThiago Jung Bauermann check_template_modsig(template_desc); 18993878d505SThiago Jung Bauermann } 19003878d505SThiago Jung Bauermann 190154f03916SMimi Zohar /* d-ngv2 template field recommended for unsigned fs-verity digests */ 190254f03916SMimi Zohar if (!result && entry->action == MEASURE && 190354f03916SMimi Zohar entry->flags & IMA_VERITY_REQUIRED) { 190454f03916SMimi Zohar template_desc = entry->template ? entry->template : 190554f03916SMimi Zohar ima_template_desc_current(); 190654f03916SMimi Zohar check_template_field(template_desc, "d-ngv2", 190754f03916SMimi Zohar "verity rules should include d-ngv2"); 190854f03916SMimi Zohar } 190954f03916SMimi Zohar 1910b0d5de4dSEric Paris audit_log_format(ab, "res=%d", !result); 19114af4662fSMimi Zohar audit_log_end(ab); 19124af4662fSMimi Zohar return result; 19134af4662fSMimi Zohar } 19144af4662fSMimi Zohar 19154af4662fSMimi Zohar /** 191607f6a794SMimi Zohar * ima_parse_add_rule - add a rule to ima_policy_rules 191795526d13SRoberto Sassu * @rule: ima measurement policy rule 19184af4662fSMimi Zohar * 191938d859f9SPetko Manolov * Avoid locking by allowing just one writer at a time in ima_write_policy() 19206ccd0456SEric Paris * Returns the length of the rule parsed, an error code on failure 19214af4662fSMimi Zohar */ 19226ccd0456SEric Paris ssize_t ima_parse_add_rule(char *rule) 19234af4662fSMimi Zohar { 192452a13284SMimi Zohar static const char op[] = "update_policy"; 19256ccd0456SEric Paris char *p; 192607f6a794SMimi Zohar struct ima_rule_entry *entry; 19276ccd0456SEric Paris ssize_t result, len; 19284af4662fSMimi Zohar int audit_info = 0; 19294af4662fSMimi Zohar 1930272a6e90SDmitry Kasatkin p = strsep(&rule, "\n"); 1931272a6e90SDmitry Kasatkin len = strlen(p) + 1; 19327178784fSDmitry Kasatkin p += strspn(p, " \t"); 1933272a6e90SDmitry Kasatkin 19347178784fSDmitry Kasatkin if (*p == '#' || *p == '\0') 1935272a6e90SDmitry Kasatkin return len; 1936272a6e90SDmitry Kasatkin 19374af4662fSMimi Zohar entry = kzalloc(sizeof(*entry), GFP_KERNEL); 19384af4662fSMimi Zohar if (!entry) { 19394af4662fSMimi Zohar integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 19404af4662fSMimi Zohar NULL, op, "-ENOMEM", -ENOMEM, audit_info); 19414af4662fSMimi Zohar return -ENOMEM; 19424af4662fSMimi Zohar } 19434af4662fSMimi Zohar 19444af4662fSMimi Zohar INIT_LIST_HEAD(&entry->list); 19454af4662fSMimi Zohar 19466ccd0456SEric Paris result = ima_parse_rule(p, entry); 19477233e3eeSEric Paris if (result) { 19482bdd737cSTyler Hicks ima_free_rule(entry); 1949523979adSMimi Zohar integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 19507e9001f6SRichard Guy Briggs NULL, op, "invalid-policy", result, 1951523979adSMimi Zohar audit_info); 19524af4662fSMimi Zohar return result; 19534af4662fSMimi Zohar } 19544af4662fSMimi Zohar 195538d859f9SPetko Manolov list_add_tail(&entry->list, &ima_temp_rules); 19567233e3eeSEric Paris 19577233e3eeSEric Paris return len; 19587233e3eeSEric Paris } 19597233e3eeSEric Paris 196038d859f9SPetko Manolov /** 1961b8dc5794SRandy Dunlap * ima_delete_rules() - called to cleanup invalid in-flight policy. 1962b8dc5794SRandy Dunlap * 196338d859f9SPetko Manolov * We don't need locking as we operate on the temp list, which is 196438d859f9SPetko Manolov * different from the active one. There is also only one user of 196538d859f9SPetko Manolov * ima_delete_rules() at a time. 196638d859f9SPetko Manolov */ 196764c61d80SJames Morris void ima_delete_rules(void) 19684af4662fSMimi Zohar { 196907f6a794SMimi Zohar struct ima_rule_entry *entry, *tmp; 19704af4662fSMimi Zohar 19716ad6afa1SMimi Zohar temp_ima_appraise = 0; 197238d859f9SPetko Manolov list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) { 19734af4662fSMimi Zohar list_del(&entry->list); 1974465aee77STyler Hicks ima_free_rule(entry); 19754af4662fSMimi Zohar } 19764af4662fSMimi Zohar } 197780eae209SPetko Manolov 197834e980bbSLakshmi Ramasubramanian #define __ima_hook_stringify(func, str) (#func), 197939b07096SThiago Jung Bauermann 198039b07096SThiago Jung Bauermann const char *const func_tokens[] = { 198139b07096SThiago Jung Bauermann __ima_hooks(__ima_hook_stringify) 198239b07096SThiago Jung Bauermann }; 198339b07096SThiago Jung Bauermann 198480eae209SPetko Manolov #ifdef CONFIG_IMA_READ_POLICY 198580eae209SPetko Manolov enum { 198680eae209SPetko Manolov mask_exec = 0, mask_write, mask_read, mask_append 198780eae209SPetko Manolov }; 198880eae209SPetko Manolov 1989bb543e39SThiago Jung Bauermann static const char *const mask_tokens[] = { 19908cdc23a3SRoberto Sassu "^MAY_EXEC", 19918cdc23a3SRoberto Sassu "^MAY_WRITE", 19928cdc23a3SRoberto Sassu "^MAY_READ", 19938cdc23a3SRoberto Sassu "^MAY_APPEND" 199480eae209SPetko Manolov }; 199580eae209SPetko Manolov 199680eae209SPetko Manolov void *ima_policy_start(struct seq_file *m, loff_t *pos) 199780eae209SPetko Manolov { 199880eae209SPetko Manolov loff_t l = *pos; 199980eae209SPetko Manolov struct ima_rule_entry *entry; 2000eb0782bbSliqiong struct list_head *ima_rules_tmp; 200180eae209SPetko Manolov 200280eae209SPetko Manolov rcu_read_lock(); 2003eb0782bbSliqiong ima_rules_tmp = rcu_dereference(ima_rules); 2004eb0782bbSliqiong list_for_each_entry_rcu(entry, ima_rules_tmp, list) { 200580eae209SPetko Manolov if (!l--) { 200680eae209SPetko Manolov rcu_read_unlock(); 200780eae209SPetko Manolov return entry; 200880eae209SPetko Manolov } 200980eae209SPetko Manolov } 201080eae209SPetko Manolov rcu_read_unlock(); 201180eae209SPetko Manolov return NULL; 201280eae209SPetko Manolov } 201380eae209SPetko Manolov 201480eae209SPetko Manolov void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) 201580eae209SPetko Manolov { 201680eae209SPetko Manolov struct ima_rule_entry *entry = v; 201780eae209SPetko Manolov 201880eae209SPetko Manolov rcu_read_lock(); 201980eae209SPetko Manolov entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list); 202080eae209SPetko Manolov rcu_read_unlock(); 202180eae209SPetko Manolov (*pos)++; 202280eae209SPetko Manolov 2023eb0782bbSliqiong return (&entry->list == &ima_default_rules || 2024eb0782bbSliqiong &entry->list == &ima_policy_rules) ? NULL : entry; 202580eae209SPetko Manolov } 202680eae209SPetko Manolov 202780eae209SPetko Manolov void ima_policy_stop(struct seq_file *m, void *v) 202880eae209SPetko Manolov { 202980eae209SPetko Manolov } 203080eae209SPetko Manolov 20311a9430dbSMimi Zohar #define pt(token) policy_tokens[token].pattern 203280eae209SPetko Manolov #define mt(token) mask_tokens[token] 203380eae209SPetko Manolov 2034b5269ab3SMimi Zohar /* 2035b5269ab3SMimi Zohar * policy_func_show - display the ima_hooks policy rule 2036b5269ab3SMimi Zohar */ 2037b5269ab3SMimi Zohar static void policy_func_show(struct seq_file *m, enum ima_hooks func) 2038b5269ab3SMimi Zohar { 20392663218bSThiago Jung Bauermann if (func > 0 && func < MAX_CHECK) 20402663218bSThiago Jung Bauermann seq_printf(m, "func=%s ", func_tokens[func]); 20412663218bSThiago Jung Bauermann else 20422663218bSThiago Jung Bauermann seq_printf(m, "func=%d ", func); 2043b5269ab3SMimi Zohar } 2044b5269ab3SMimi Zohar 2045176377d9STyler Hicks static void ima_show_rule_opt_list(struct seq_file *m, 2046176377d9STyler Hicks const struct ima_rule_opt_list *opt_list) 2047176377d9STyler Hicks { 2048176377d9STyler Hicks size_t i; 2049176377d9STyler Hicks 2050176377d9STyler Hicks for (i = 0; i < opt_list->count; i++) 2051176377d9STyler Hicks seq_printf(m, "%s%s", i ? "|" : "", opt_list->items[i]); 2052176377d9STyler Hicks } 2053176377d9STyler Hicks 2054583a80aeSTHOBY Simon static void ima_policy_show_appraise_algos(struct seq_file *m, 2055583a80aeSTHOBY Simon unsigned int allowed_hashes) 2056583a80aeSTHOBY Simon { 2057583a80aeSTHOBY Simon int idx, list_size = 0; 2058583a80aeSTHOBY Simon 2059583a80aeSTHOBY Simon for (idx = 0; idx < HASH_ALGO__LAST; idx++) { 2060583a80aeSTHOBY Simon if (!(allowed_hashes & (1U << idx))) 2061583a80aeSTHOBY Simon continue; 2062583a80aeSTHOBY Simon 2063583a80aeSTHOBY Simon /* only add commas if the list contains multiple entries */ 2064583a80aeSTHOBY Simon if (list_size++) 2065583a80aeSTHOBY Simon seq_puts(m, ","); 2066583a80aeSTHOBY Simon 2067583a80aeSTHOBY Simon seq_puts(m, hash_algo_name[idx]); 2068583a80aeSTHOBY Simon } 2069583a80aeSTHOBY Simon } 2070583a80aeSTHOBY Simon 207180eae209SPetko Manolov int ima_policy_show(struct seq_file *m, void *v) 207280eae209SPetko Manolov { 207380eae209SPetko Manolov struct ima_rule_entry *entry = v; 2074b8b57278SAndy Shevchenko int i; 207580eae209SPetko Manolov char tbuf[64] = {0,}; 20768cdc23a3SRoberto Sassu int offset = 0; 207780eae209SPetko Manolov 207880eae209SPetko Manolov rcu_read_lock(); 207980eae209SPetko Manolov 208089677197SStefan Berger /* Do not print rules with inactive LSM labels */ 208189677197SStefan Berger for (i = 0; i < MAX_LSM_RULES; i++) { 208289677197SStefan Berger if (entry->lsm[i].args_p && !entry->lsm[i].rule) { 208389677197SStefan Berger rcu_read_unlock(); 208489677197SStefan Berger return 0; 208589677197SStefan Berger } 208689677197SStefan Berger } 208789677197SStefan Berger 208880eae209SPetko Manolov if (entry->action & MEASURE) 208980eae209SPetko Manolov seq_puts(m, pt(Opt_measure)); 209080eae209SPetko Manolov if (entry->action & DONT_MEASURE) 209180eae209SPetko Manolov seq_puts(m, pt(Opt_dont_measure)); 209280eae209SPetko Manolov if (entry->action & APPRAISE) 209380eae209SPetko Manolov seq_puts(m, pt(Opt_appraise)); 209480eae209SPetko Manolov if (entry->action & DONT_APPRAISE) 209580eae209SPetko Manolov seq_puts(m, pt(Opt_dont_appraise)); 209680eae209SPetko Manolov if (entry->action & AUDIT) 209780eae209SPetko Manolov seq_puts(m, pt(Opt_audit)); 2098da1b0029SMimi Zohar if (entry->action & HASH) 2099da1b0029SMimi Zohar seq_puts(m, pt(Opt_hash)); 2100da1b0029SMimi Zohar if (entry->action & DONT_HASH) 2101da1b0029SMimi Zohar seq_puts(m, pt(Opt_dont_hash)); 210280eae209SPetko Manolov 210380eae209SPetko Manolov seq_puts(m, " "); 210480eae209SPetko Manolov 2105b5269ab3SMimi Zohar if (entry->flags & IMA_FUNC) 2106b5269ab3SMimi Zohar policy_func_show(m, entry->func); 210780eae209SPetko Manolov 21088cdc23a3SRoberto Sassu if ((entry->flags & IMA_MASK) || (entry->flags & IMA_INMASK)) { 21098cdc23a3SRoberto Sassu if (entry->flags & IMA_MASK) 21108cdc23a3SRoberto Sassu offset = 1; 211180eae209SPetko Manolov if (entry->mask & MAY_EXEC) 21128cdc23a3SRoberto Sassu seq_printf(m, pt(Opt_mask), mt(mask_exec) + offset); 211380eae209SPetko Manolov if (entry->mask & MAY_WRITE) 21148cdc23a3SRoberto Sassu seq_printf(m, pt(Opt_mask), mt(mask_write) + offset); 211580eae209SPetko Manolov if (entry->mask & MAY_READ) 21168cdc23a3SRoberto Sassu seq_printf(m, pt(Opt_mask), mt(mask_read) + offset); 211780eae209SPetko Manolov if (entry->mask & MAY_APPEND) 21188cdc23a3SRoberto Sassu seq_printf(m, pt(Opt_mask), mt(mask_append) + offset); 211980eae209SPetko Manolov seq_puts(m, " "); 212080eae209SPetko Manolov } 212180eae209SPetko Manolov 212280eae209SPetko Manolov if (entry->flags & IMA_FSMAGIC) { 212380eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "0x%lx", entry->fsmagic); 212480eae209SPetko Manolov seq_printf(m, pt(Opt_fsmagic), tbuf); 212580eae209SPetko Manolov seq_puts(m, " "); 212680eae209SPetko Manolov } 212780eae209SPetko Manolov 2128f1b08bbcSMimi Zohar if (entry->flags & IMA_FSNAME) { 2129f1b08bbcSMimi Zohar snprintf(tbuf, sizeof(tbuf), "%s", entry->fsname); 2130f1b08bbcSMimi Zohar seq_printf(m, pt(Opt_fsname), tbuf); 2131f1b08bbcSMimi Zohar seq_puts(m, " "); 2132f1b08bbcSMimi Zohar } 2133f1b08bbcSMimi Zohar 21342b60c0ecSLakshmi Ramasubramanian if (entry->flags & IMA_KEYRINGS) { 2135176377d9STyler Hicks seq_puts(m, "keyrings="); 2136176377d9STyler Hicks ima_show_rule_opt_list(m, entry->keyrings); 21372b60c0ecSLakshmi Ramasubramanian seq_puts(m, " "); 21382b60c0ecSLakshmi Ramasubramanian } 21392b60c0ecSLakshmi Ramasubramanian 214047d76a48STushar Sugandhi if (entry->flags & IMA_LABEL) { 214147d76a48STushar Sugandhi seq_puts(m, "label="); 214247d76a48STushar Sugandhi ima_show_rule_opt_list(m, entry->label); 214347d76a48STushar Sugandhi seq_puts(m, " "); 214447d76a48STushar Sugandhi } 214547d76a48STushar Sugandhi 21460260643cSEric Richter if (entry->flags & IMA_PCR) { 21470260643cSEric Richter snprintf(tbuf, sizeof(tbuf), "%d", entry->pcr); 21480260643cSEric Richter seq_printf(m, pt(Opt_pcr), tbuf); 21490260643cSEric Richter seq_puts(m, " "); 21500260643cSEric Richter } 21510260643cSEric Richter 215280eae209SPetko Manolov if (entry->flags & IMA_FSUUID) { 2153787d8c53SChristoph Hellwig seq_printf(m, "fsuuid=%pU", &entry->fsuuid); 215480eae209SPetko Manolov seq_puts(m, " "); 215580eae209SPetko Manolov } 215680eae209SPetko Manolov 215780eae209SPetko Manolov if (entry->flags & IMA_UID) { 215880eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); 21593dd0c8d0SMikhail Kurinnoi if (entry->uid_op == &uid_gt) 21603dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_uid_gt), tbuf); 21613dd0c8d0SMikhail Kurinnoi else if (entry->uid_op == &uid_lt) 21623dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_uid_lt), tbuf); 21633dd0c8d0SMikhail Kurinnoi else 21643dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_uid_eq), tbuf); 216580eae209SPetko Manolov seq_puts(m, " "); 216680eae209SPetko Manolov } 216780eae209SPetko Manolov 216880eae209SPetko Manolov if (entry->flags & IMA_EUID) { 216980eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); 21703dd0c8d0SMikhail Kurinnoi if (entry->uid_op == &uid_gt) 21713dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_euid_gt), tbuf); 21723dd0c8d0SMikhail Kurinnoi else if (entry->uid_op == &uid_lt) 21733dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_euid_lt), tbuf); 21743dd0c8d0SMikhail Kurinnoi else 21753dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_euid_eq), tbuf); 217680eae209SPetko Manolov seq_puts(m, " "); 217780eae209SPetko Manolov } 217880eae209SPetko Manolov 217940224c41SCurtis Veit if (entry->flags & IMA_GID) { 218040224c41SCurtis Veit snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid)); 218140224c41SCurtis Veit if (entry->gid_op == &gid_gt) 218240224c41SCurtis Veit seq_printf(m, pt(Opt_gid_gt), tbuf); 218340224c41SCurtis Veit else if (entry->gid_op == &gid_lt) 218440224c41SCurtis Veit seq_printf(m, pt(Opt_gid_lt), tbuf); 218540224c41SCurtis Veit else 218640224c41SCurtis Veit seq_printf(m, pt(Opt_gid_eq), tbuf); 218740224c41SCurtis Veit seq_puts(m, " "); 218840224c41SCurtis Veit } 218940224c41SCurtis Veit 219040224c41SCurtis Veit if (entry->flags & IMA_EGID) { 219140224c41SCurtis Veit snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid)); 219240224c41SCurtis Veit if (entry->gid_op == &gid_gt) 219340224c41SCurtis Veit seq_printf(m, pt(Opt_egid_gt), tbuf); 219440224c41SCurtis Veit else if (entry->gid_op == &gid_lt) 219540224c41SCurtis Veit seq_printf(m, pt(Opt_egid_lt), tbuf); 219640224c41SCurtis Veit else 219740224c41SCurtis Veit seq_printf(m, pt(Opt_egid_eq), tbuf); 219840224c41SCurtis Veit seq_puts(m, " "); 219940224c41SCurtis Veit } 220040224c41SCurtis Veit 220180eae209SPetko Manolov if (entry->flags & IMA_FOWNER) { 220280eae209SPetko Manolov snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); 22038e27a7aeSChristian Brauner if (entry->fowner_op == &vfsuid_gt_kuid) 22043dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_fowner_gt), tbuf); 22058e27a7aeSChristian Brauner else if (entry->fowner_op == &vfsuid_lt_kuid) 22063dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_fowner_lt), tbuf); 22073dd0c8d0SMikhail Kurinnoi else 22083dd0c8d0SMikhail Kurinnoi seq_printf(m, pt(Opt_fowner_eq), tbuf); 220980eae209SPetko Manolov seq_puts(m, " "); 221080eae209SPetko Manolov } 221180eae209SPetko Manolov 221240224c41SCurtis Veit if (entry->flags & IMA_FGROUP) { 221340224c41SCurtis Veit snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup)); 22148e27a7aeSChristian Brauner if (entry->fgroup_op == &vfsgid_gt_kgid) 221540224c41SCurtis Veit seq_printf(m, pt(Opt_fgroup_gt), tbuf); 22168e27a7aeSChristian Brauner else if (entry->fgroup_op == &vfsgid_lt_kgid) 221740224c41SCurtis Veit seq_printf(m, pt(Opt_fgroup_lt), tbuf); 221840224c41SCurtis Veit else 221940224c41SCurtis Veit seq_printf(m, pt(Opt_fgroup_eq), tbuf); 222040224c41SCurtis Veit seq_puts(m, " "); 222140224c41SCurtis Veit } 222240224c41SCurtis Veit 2223583a80aeSTHOBY Simon if (entry->flags & IMA_VALIDATE_ALGOS) { 2224583a80aeSTHOBY Simon seq_puts(m, "appraise_algos="); 2225583a80aeSTHOBY Simon ima_policy_show_appraise_algos(m, entry->allowed_algos); 2226583a80aeSTHOBY Simon seq_puts(m, " "); 2227583a80aeSTHOBY Simon } 2228583a80aeSTHOBY Simon 222980eae209SPetko Manolov for (i = 0; i < MAX_LSM_RULES; i++) { 223080eae209SPetko Manolov if (entry->lsm[i].rule) { 223180eae209SPetko Manolov switch (i) { 223280eae209SPetko Manolov case LSM_OBJ_USER: 223380eae209SPetko Manolov seq_printf(m, pt(Opt_obj_user), 2234aa0c0227STyler Hicks entry->lsm[i].args_p); 223580eae209SPetko Manolov break; 223680eae209SPetko Manolov case LSM_OBJ_ROLE: 223780eae209SPetko Manolov seq_printf(m, pt(Opt_obj_role), 2238aa0c0227STyler Hicks entry->lsm[i].args_p); 223980eae209SPetko Manolov break; 224080eae209SPetko Manolov case LSM_OBJ_TYPE: 224180eae209SPetko Manolov seq_printf(m, pt(Opt_obj_type), 2242aa0c0227STyler Hicks entry->lsm[i].args_p); 224380eae209SPetko Manolov break; 224480eae209SPetko Manolov case LSM_SUBJ_USER: 224580eae209SPetko Manolov seq_printf(m, pt(Opt_subj_user), 2246aa0c0227STyler Hicks entry->lsm[i].args_p); 224780eae209SPetko Manolov break; 224880eae209SPetko Manolov case LSM_SUBJ_ROLE: 224980eae209SPetko Manolov seq_printf(m, pt(Opt_subj_role), 2250aa0c0227STyler Hicks entry->lsm[i].args_p); 225180eae209SPetko Manolov break; 225280eae209SPetko Manolov case LSM_SUBJ_TYPE: 225380eae209SPetko Manolov seq_printf(m, pt(Opt_subj_type), 2254aa0c0227STyler Hicks entry->lsm[i].args_p); 225580eae209SPetko Manolov break; 225680eae209SPetko Manolov } 22575350ceb0SClay Chang seq_puts(m, " "); 225880eae209SPetko Manolov } 225980eae209SPetko Manolov } 226019453ce0SMatthew Garrett if (entry->template) 226119453ce0SMatthew Garrett seq_printf(m, "template=%s ", entry->template->name); 22629044d627SThiago Jung Bauermann if (entry->flags & IMA_DIGSIG_REQUIRED) { 2263398c42e2SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 2264398c42e2SMimi Zohar seq_puts(m, "appraise_type=sigv3 "); 2265398c42e2SMimi Zohar else if (entry->flags & IMA_MODSIG_ALLOWED) 22669044d627SThiago Jung Bauermann seq_puts(m, "appraise_type=imasig|modsig "); 22679044d627SThiago Jung Bauermann else 226880eae209SPetko Manolov seq_puts(m, "appraise_type=imasig "); 22699044d627SThiago Jung Bauermann } 227054f03916SMimi Zohar if (entry->flags & IMA_VERITY_REQUIRED) 227154f03916SMimi Zohar seq_puts(m, "digest_type=verity "); 227280eae209SPetko Manolov if (entry->flags & IMA_PERMIT_DIRECTIO) 227380eae209SPetko Manolov seq_puts(m, "permit_directio "); 227480eae209SPetko Manolov rcu_read_unlock(); 227580eae209SPetko Manolov seq_puts(m, "\n"); 227680eae209SPetko Manolov return 0; 227780eae209SPetko Manolov } 227880eae209SPetko Manolov #endif /* CONFIG_IMA_READ_POLICY */ 227929d3c1c8SMatthew Garrett 228029d3c1c8SMatthew Garrett #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) 228129d3c1c8SMatthew Garrett /* 228229d3c1c8SMatthew Garrett * ima_appraise_signature: whether IMA will appraise a given function using 228329d3c1c8SMatthew Garrett * an IMA digital signature. This is restricted to cases where the kernel 228429d3c1c8SMatthew Garrett * has a set of built-in trusted keys in order to avoid an attacker simply 228529d3c1c8SMatthew Garrett * loading additional keys. 228629d3c1c8SMatthew Garrett */ 228729d3c1c8SMatthew Garrett bool ima_appraise_signature(enum kernel_read_file_id id) 228829d3c1c8SMatthew Garrett { 228929d3c1c8SMatthew Garrett struct ima_rule_entry *entry; 229029d3c1c8SMatthew Garrett bool found = false; 229129d3c1c8SMatthew Garrett enum ima_hooks func; 2292eb0782bbSliqiong struct list_head *ima_rules_tmp; 229329d3c1c8SMatthew Garrett 229429d3c1c8SMatthew Garrett if (id >= READING_MAX_ID) 229529d3c1c8SMatthew Garrett return false; 229629d3c1c8SMatthew Garrett 2297543ce63bSEric Snowberg if (id == READING_KEXEC_IMAGE && !(ima_appraise & IMA_APPRAISE_ENFORCE) 2298543ce63bSEric Snowberg && security_locked_down(LOCKDOWN_KEXEC)) 2299543ce63bSEric Snowberg return false; 2300543ce63bSEric Snowberg 230129d3c1c8SMatthew Garrett func = read_idmap[id] ?: FILE_CHECK; 230229d3c1c8SMatthew Garrett 230329d3c1c8SMatthew Garrett rcu_read_lock(); 2304eb0782bbSliqiong ima_rules_tmp = rcu_dereference(ima_rules); 2305eb0782bbSliqiong list_for_each_entry_rcu(entry, ima_rules_tmp, list) { 230629d3c1c8SMatthew Garrett if (entry->action != APPRAISE) 230729d3c1c8SMatthew Garrett continue; 230829d3c1c8SMatthew Garrett 230929d3c1c8SMatthew Garrett /* 231029d3c1c8SMatthew Garrett * A generic entry will match, but otherwise require that it 231129d3c1c8SMatthew Garrett * match the func we're looking for 231229d3c1c8SMatthew Garrett */ 231329d3c1c8SMatthew Garrett if (entry->func && entry->func != func) 231429d3c1c8SMatthew Garrett continue; 231529d3c1c8SMatthew Garrett 231629d3c1c8SMatthew Garrett /* 231729d3c1c8SMatthew Garrett * We require this to be a digital signature, not a raw IMA 231829d3c1c8SMatthew Garrett * hash. 231929d3c1c8SMatthew Garrett */ 232029d3c1c8SMatthew Garrett if (entry->flags & IMA_DIGSIG_REQUIRED) 232129d3c1c8SMatthew Garrett found = true; 232229d3c1c8SMatthew Garrett 232329d3c1c8SMatthew Garrett /* 232429d3c1c8SMatthew Garrett * We've found a rule that matches, so break now even if it 232529d3c1c8SMatthew Garrett * didn't require a digital signature - a later rule that does 232629d3c1c8SMatthew Garrett * won't override it, so would be a false positive. 232729d3c1c8SMatthew Garrett */ 232829d3c1c8SMatthew Garrett break; 232929d3c1c8SMatthew Garrett } 233029d3c1c8SMatthew Garrett 233129d3c1c8SMatthew Garrett rcu_read_unlock(); 233229d3c1c8SMatthew Garrett return found; 233329d3c1c8SMatthew Garrett } 233429d3c1c8SMatthew Garrett #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */ 2335