Commit | Line | Data |
---|---|---|
b886d83c | 1 | // SPDX-License-Identifier: GPL-2.0-only |
3323eec9 MZ |
2 | /* |
3 | * Copyright (C) 2008 IBM Corporation | |
4 | * Author: Mimi Zohar <zohar@us.ibm.com> | |
5 | * | |
3323eec9 | 6 | * ima_policy.c |
2bb930ab | 7 | * - initialize default measure policy rules |
3323eec9 | 8 | */ |
3878d505 | 9 | |
876979c9 | 10 | #include <linux/init.h> |
3323eec9 | 11 | #include <linux/list.h> |
b89999d0 | 12 | #include <linux/kernel_read_file.h> |
cf222217 | 13 | #include <linux/fs.h> |
3323eec9 MZ |
14 | #include <linux/security.h> |
15 | #include <linux/magic.h> | |
4af4662f | 16 | #include <linux/parser.h> |
5a0e3ad6 | 17 | #include <linux/slab.h> |
38d859f9 | 18 | #include <linux/rculist.h> |
85865c1f | 19 | #include <linux/genhd.h> |
80eae209 | 20 | #include <linux/seq_file.h> |
61917062 | 21 | #include <linux/ima.h> |
3323eec9 MZ |
22 | |
23 | #include "ima.h" | |
24 | ||
25 | /* flags definitions */ | |
2bb930ab DK |
26 | #define IMA_FUNC 0x0001 |
27 | #define IMA_MASK 0x0002 | |
3323eec9 MZ |
28 | #define IMA_FSMAGIC 0x0004 |
29 | #define IMA_UID 0x0008 | |
07f6a794 | 30 | #define IMA_FOWNER 0x0010 |
85865c1f | 31 | #define IMA_FSUUID 0x0020 |
4351c294 | 32 | #define IMA_INMASK 0x0040 |
139069ef | 33 | #define IMA_EUID 0x0080 |
0260643c | 34 | #define IMA_PCR 0x0100 |
f1b08bbc | 35 | #define IMA_FSNAME 0x0200 |
2b60c0ec | 36 | #define IMA_KEYRINGS 0x0400 |
47d76a48 | 37 | #define IMA_LABEL 0x0800 |
1624dc00 | 38 | #define IMA_VALIDATE_ALGOS 0x1000 |
40224c41 CV |
39 | #define IMA_GID 0x2000 |
40 | #define IMA_EGID 0x4000 | |
41 | #define IMA_FGROUP 0x8000 | |
3323eec9 | 42 | |
45e2472e DK |
43 | #define UNKNOWN 0 |
44 | #define MEASURE 0x0001 /* same as IMA_MEASURE */ | |
45 | #define DONT_MEASURE 0x0002 | |
46 | #define APPRAISE 0x0004 /* same as IMA_APPRAISE */ | |
47 | #define DONT_APPRAISE 0x0008 | |
e7c568e0 | 48 | #define AUDIT 0x0040 |
da1b0029 MZ |
49 | #define HASH 0x0100 |
50 | #define DONT_HASH 0x0200 | |
4af4662f | 51 | |
0260643c | 52 | #define INVALID_PCR(a) (((a) < 0) || \ |
c593642c | 53 | (a) >= (sizeof_field(struct integrity_iint_cache, measured_pcrs) * 8)) |
0260643c | 54 | |
a756024e | 55 | int ima_policy_flag; |
6ad6afa1 | 56 | static int temp_ima_appraise; |
ef96837b | 57 | static int build_ima_appraise __ro_after_init; |
a756024e | 58 | |
4f2946aa TS |
59 | atomic_t ima_setxattr_allowed_hash_algorithms; |
60 | ||
4af4662f MZ |
61 | #define MAX_LSM_RULES 6 |
62 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | |
63 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE | |
64 | }; | |
3323eec9 | 65 | |
24fd03c8 MZ |
66 | enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; |
67 | ||
c52657d9 NJ |
68 | enum policy_rule_list { IMA_DEFAULT_POLICY = 1, IMA_CUSTOM_POLICY }; |
69 | ||
176377d9 TH |
70 | struct ima_rule_opt_list { |
71 | size_t count; | |
72 | char *items[]; | |
73 | }; | |
74 | ||
07f6a794 | 75 | struct ima_rule_entry { |
3323eec9 | 76 | struct list_head list; |
2fe5d6de | 77 | int action; |
3323eec9 MZ |
78 | unsigned int flags; |
79 | enum ima_hooks func; | |
80 | int mask; | |
81 | unsigned long fsmagic; | |
787d8c53 | 82 | uuid_t fsuuid; |
8b94eea4 | 83 | kuid_t uid; |
40224c41 | 84 | kgid_t gid; |
88265322 | 85 | kuid_t fowner; |
40224c41 | 86 | kgid_t fgroup; |
30d8764a | 87 | bool (*uid_op)(kuid_t cred_uid, kuid_t rule_uid); /* Handlers for operators */ |
40224c41 | 88 | bool (*gid_op)(kgid_t cred_gid, kgid_t rule_gid); |
30d8764a | 89 | bool (*fowner_op)(kuid_t cred_uid, kuid_t rule_uid); /* uid_eq(), uid_gt(), uid_lt() */ |
40224c41 | 90 | bool (*fgroup_op)(kgid_t cred_gid, kgid_t rule_gid); /* gid_eq(), gid_gt(), gid_lt() */ |
0260643c | 91 | int pcr; |
1624dc00 | 92 | unsigned int allowed_algos; /* bitfield of allowed hash algorithms */ |
4af4662f MZ |
93 | struct { |
94 | void *rule; /* LSM file metadata specific */ | |
aa0c0227 | 95 | char *args_p; /* audit value */ |
4af4662f MZ |
96 | int type; /* audit type */ |
97 | } lsm[MAX_LSM_RULES]; | |
f1b08bbc | 98 | char *fsname; |
176377d9 | 99 | struct ima_rule_opt_list *keyrings; /* Measure keys added to these keyrings */ |
47d76a48 | 100 | struct ima_rule_opt_list *label; /* Measure data grouped under this label */ |
19453ce0 | 101 | struct ima_template_desc *template; |
3323eec9 MZ |
102 | }; |
103 | ||
1624dc00 TS |
104 | /* |
105 | * sanity check in case the kernels gains more hash algorithms that can | |
106 | * fit in an unsigned int | |
107 | */ | |
108 | static_assert( | |
109 | 8 * sizeof(unsigned int) >= HASH_ALGO__LAST, | |
110 | "The bitfield allowed_algos in ima_rule_entry is too small to contain all the supported hash algorithms, consider using a bigger type"); | |
111 | ||
5789ba3b EP |
112 | /* |
113 | * Without LSM specific knowledge, the default policy can only be | |
40224c41 CV |
114 | * written in terms of .action, .func, .mask, .fsmagic, .uid, .gid, |
115 | * .fowner, and .fgroup | |
4af4662f | 116 | */ |
5789ba3b EP |
117 | |
118 | /* | |
119 | * The minimum rule set to allow for full TCB coverage. Measures all files | |
120 | * opened or mmap for exec and everything read by root. Dangerous because | |
121 | * normal users can easily run the machine out of memory simply building | |
122 | * and running executables. | |
123 | */ | |
bad4417b | 124 | static struct ima_rule_entry dont_measure_rules[] __ro_after_init = { |
2bb930ab DK |
125 | {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
126 | {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, | |
127 | {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, | |
128 | {.action = DONT_MEASURE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, | |
129 | {.action = DONT_MEASURE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, | |
130 | {.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, | |
131 | {.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, | |
132 | {.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, | |
1c070b18 | 133 | {.action = DONT_MEASURE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, |
6438de9f RS |
134 | {.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC, |
135 | .flags = IMA_FSMAGIC}, | |
82e3bb4d LA |
136 | {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC, |
137 | .flags = IMA_FSMAGIC}, | |
060190fb MZ |
138 | {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, |
139 | {.action = DONT_MEASURE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC} | |
24fd03c8 MZ |
140 | }; |
141 | ||
bad4417b | 142 | static struct ima_rule_entry original_measurement_rules[] __ro_after_init = { |
24fd03c8 MZ |
143 | {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, |
144 | .flags = IMA_FUNC | IMA_MASK}, | |
145 | {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, | |
146 | .flags = IMA_FUNC | IMA_MASK}, | |
147 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, | |
3dd0c8d0 MK |
148 | .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, |
149 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | |
24fd03c8 MZ |
150 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, |
151 | {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, | |
152 | }; | |
153 | ||
bad4417b | 154 | static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { |
2bb930ab | 155 | {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, |
3323eec9 | 156 | .flags = IMA_FUNC | IMA_MASK}, |
2bb930ab | 157 | {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, |
3323eec9 | 158 | .flags = IMA_FUNC | IMA_MASK}, |
24fd03c8 | 159 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, |
3dd0c8d0 MK |
160 | .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, |
161 | .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, | |
24fd03c8 | 162 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, |
3dd0c8d0 MK |
163 | .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, |
164 | .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, | |
2bb930ab | 165 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, |
5a9196d7 | 166 | {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, |
19f8a847 | 167 | {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, |
3323eec9 MZ |
168 | }; |
169 | ||
bad4417b | 170 | static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { |
2bb930ab DK |
171 | {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
172 | {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, | |
173 | {.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, | |
174 | {.action = DONT_APPRAISE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, | |
175 | {.action = DONT_APPRAISE, .fsmagic = RAMFS_MAGIC, .flags = IMA_FSMAGIC}, | |
176 | {.action = DONT_APPRAISE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, | |
177 | {.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, | |
178 | {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, | |
179 | {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, | |
1c070b18 | 180 | {.action = DONT_APPRAISE, .fsmagic = SMACK_MAGIC, .flags = IMA_FSMAGIC}, |
cd025f7f | 181 | {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, |
060190fb | 182 | {.action = DONT_APPRAISE, .fsmagic = EFIVARFS_MAGIC, .flags = IMA_FSMAGIC}, |
2bb930ab | 183 | {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
82e3bb4d | 184 | {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
95ee08fa MZ |
185 | #ifdef CONFIG_IMA_WRITE_POLICY |
186 | {.action = APPRAISE, .func = POLICY_CHECK, | |
187 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
188 | #endif | |
c57782c1 | 189 | #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT |
3dd0c8d0 MK |
190 | {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, |
191 | .flags = IMA_FOWNER}, | |
c57782c1 DK |
192 | #else |
193 | /* force signature */ | |
3dd0c8d0 | 194 | {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, |
c57782c1 DK |
195 | .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, |
196 | #endif | |
07f6a794 MZ |
197 | }; |
198 | ||
ef96837b MZ |
199 | static struct ima_rule_entry build_appraise_rules[] __ro_after_init = { |
200 | #ifdef CONFIG_IMA_APPRAISE_REQUIRE_MODULE_SIGS | |
201 | {.action = APPRAISE, .func = MODULE_CHECK, | |
202 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
203 | #endif | |
204 | #ifdef CONFIG_IMA_APPRAISE_REQUIRE_FIRMWARE_SIGS | |
205 | {.action = APPRAISE, .func = FIRMWARE_CHECK, | |
206 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
207 | #endif | |
208 | #ifdef CONFIG_IMA_APPRAISE_REQUIRE_KEXEC_SIGS | |
209 | {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK, | |
210 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
211 | #endif | |
212 | #ifdef CONFIG_IMA_APPRAISE_REQUIRE_POLICY_SIGS | |
213 | {.action = APPRAISE, .func = POLICY_CHECK, | |
214 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
215 | #endif | |
216 | }; | |
217 | ||
503ceaef MZ |
218 | static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { |
219 | {.action = APPRAISE, .func = MODULE_CHECK, | |
220 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
221 | {.action = APPRAISE, .func = FIRMWARE_CHECK, | |
222 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
223 | {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK, | |
224 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
225 | {.action = APPRAISE, .func = POLICY_CHECK, | |
226 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
227 | }; | |
228 | ||
03cee168 LR |
229 | static struct ima_rule_entry critical_data_rules[] __ro_after_init = { |
230 | {.action = MEASURE, .func = CRITICAL_DATA, .flags = IMA_FUNC}, | |
231 | }; | |
232 | ||
61917062 | 233 | /* An array of architecture specific rules */ |
68f25290 | 234 | static struct ima_rule_entry *arch_policy_entry __ro_after_init; |
61917062 | 235 | |
07f6a794 MZ |
236 | static LIST_HEAD(ima_default_rules); |
237 | static LIST_HEAD(ima_policy_rules); | |
38d859f9 | 238 | static LIST_HEAD(ima_temp_rules); |
eb0782bb | 239 | static struct list_head __rcu *ima_rules = (struct list_head __rcu *)(&ima_default_rules); |
3323eec9 | 240 | |
24fd03c8 | 241 | static int ima_policy __initdata; |
38d859f9 | 242 | |
07f6a794 | 243 | static int __init default_measure_policy_setup(char *str) |
5789ba3b | 244 | { |
24fd03c8 MZ |
245 | if (ima_policy) |
246 | return 1; | |
247 | ||
248 | ima_policy = ORIGINAL_TCB; | |
5789ba3b EP |
249 | return 1; |
250 | } | |
07f6a794 MZ |
251 | __setup("ima_tcb", default_measure_policy_setup); |
252 | ||
33ce9549 | 253 | static bool ima_use_appraise_tcb __initdata; |
503ceaef | 254 | static bool ima_use_secure_boot __initdata; |
03cee168 | 255 | static bool ima_use_critical_data __initdata; |
9e67028e | 256 | static bool ima_fail_unverifiable_sigs __ro_after_init; |
24fd03c8 MZ |
257 | static int __init policy_setup(char *str) |
258 | { | |
33ce9549 | 259 | char *p; |
24fd03c8 | 260 | |
33ce9549 MZ |
261 | while ((p = strsep(&str, " |\n")) != NULL) { |
262 | if (*p == ' ') | |
263 | continue; | |
264 | if ((strcmp(p, "tcb") == 0) && !ima_policy) | |
265 | ima_policy = DEFAULT_TCB; | |
266 | else if (strcmp(p, "appraise_tcb") == 0) | |
39adb925 | 267 | ima_use_appraise_tcb = true; |
503ceaef | 268 | else if (strcmp(p, "secure_boot") == 0) |
39adb925 | 269 | ima_use_secure_boot = true; |
03cee168 LR |
270 | else if (strcmp(p, "critical_data") == 0) |
271 | ima_use_critical_data = true; | |
9e67028e MZ |
272 | else if (strcmp(p, "fail_securely") == 0) |
273 | ima_fail_unverifiable_sigs = true; | |
7fe2bb7e BM |
274 | else |
275 | pr_err("policy \"%s\" not found", p); | |
33ce9549 | 276 | } |
24fd03c8 MZ |
277 | |
278 | return 1; | |
279 | } | |
280 | __setup("ima_policy=", policy_setup); | |
281 | ||
07f6a794 MZ |
282 | static int __init default_appraise_policy_setup(char *str) |
283 | { | |
39adb925 | 284 | ima_use_appraise_tcb = true; |
07f6a794 MZ |
285 | return 1; |
286 | } | |
287 | __setup("ima_appraise_tcb", default_appraise_policy_setup); | |
5789ba3b | 288 | |
176377d9 TH |
289 | static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src) |
290 | { | |
291 | struct ima_rule_opt_list *opt_list; | |
292 | size_t count = 0; | |
293 | char *src_copy; | |
294 | char *cur, *next; | |
295 | size_t i; | |
296 | ||
297 | src_copy = match_strdup(src); | |
298 | if (!src_copy) | |
299 | return ERR_PTR(-ENOMEM); | |
300 | ||
301 | next = src_copy; | |
302 | while ((cur = strsep(&next, "|"))) { | |
303 | /* Don't accept an empty list item */ | |
304 | if (!(*cur)) { | |
305 | kfree(src_copy); | |
306 | return ERR_PTR(-EINVAL); | |
307 | } | |
308 | count++; | |
309 | } | |
310 | ||
311 | /* Don't accept an empty list */ | |
312 | if (!count) { | |
313 | kfree(src_copy); | |
314 | return ERR_PTR(-EINVAL); | |
315 | } | |
316 | ||
317 | opt_list = kzalloc(struct_size(opt_list, items, count), GFP_KERNEL); | |
318 | if (!opt_list) { | |
319 | kfree(src_copy); | |
320 | return ERR_PTR(-ENOMEM); | |
321 | } | |
322 | ||
323 | /* | |
324 | * strsep() has already replaced all instances of '|' with '\0', | |
325 | * leaving a byte sequence of NUL-terminated strings. Reference each | |
326 | * string with the array of items. | |
327 | * | |
328 | * IMPORTANT: Ownership of the allocated buffer is transferred from | |
329 | * src_copy to the first element in the items array. To free the | |
330 | * buffer, kfree() must only be called on the first element of the | |
331 | * array. | |
332 | */ | |
333 | for (i = 0, cur = src_copy; i < count; i++) { | |
334 | opt_list->items[i] = cur; | |
335 | cur = strchr(cur, '\0') + 1; | |
336 | } | |
337 | opt_list->count = count; | |
338 | ||
339 | return opt_list; | |
340 | } | |
341 | ||
342 | static void ima_free_rule_opt_list(struct ima_rule_opt_list *opt_list) | |
343 | { | |
344 | if (!opt_list) | |
345 | return; | |
346 | ||
347 | if (opt_list->count) { | |
348 | kfree(opt_list->items[0]); | |
349 | opt_list->count = 0; | |
350 | } | |
351 | ||
352 | kfree(opt_list); | |
353 | } | |
354 | ||
b1694245 JK |
355 | static void ima_lsm_free_rule(struct ima_rule_entry *entry) |
356 | { | |
357 | int i; | |
358 | ||
359 | for (i = 0; i < MAX_LSM_RULES; i++) { | |
b8867eed | 360 | ima_filter_rule_free(entry->lsm[i].rule); |
b1694245 JK |
361 | kfree(entry->lsm[i].args_p); |
362 | } | |
465aee77 TH |
363 | } |
364 | ||
365 | static void ima_free_rule(struct ima_rule_entry *entry) | |
366 | { | |
367 | if (!entry) | |
368 | return; | |
369 | ||
370 | /* | |
371 | * entry->template->fields may be allocated in ima_parse_rule() but that | |
372 | * reference is owned by the corresponding ima_template_desc element in | |
373 | * the defined_templates list and cannot be freed here | |
374 | */ | |
375 | kfree(entry->fsname); | |
176377d9 | 376 | ima_free_rule_opt_list(entry->keyrings); |
465aee77 | 377 | ima_lsm_free_rule(entry); |
b1694245 JK |
378 | kfree(entry); |
379 | } | |
380 | ||
381 | static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry) | |
382 | { | |
383 | struct ima_rule_entry *nentry; | |
483ec26e | 384 | int i; |
b1694245 | 385 | |
b1694245 JK |
386 | /* |
387 | * Immutable elements are copied over as pointers and data; only | |
388 | * lsm rules can change | |
389 | */ | |
f60c826d AD |
390 | nentry = kmemdup(entry, sizeof(*nentry), GFP_KERNEL); |
391 | if (!nentry) | |
392 | return NULL; | |
393 | ||
c593642c | 394 | memset(nentry->lsm, 0, sizeof_field(struct ima_rule_entry, lsm)); |
b1694245 JK |
395 | |
396 | for (i = 0; i < MAX_LSM_RULES; i++) { | |
483ec26e | 397 | if (!entry->lsm[i].args_p) |
b1694245 JK |
398 | continue; |
399 | ||
400 | nentry->lsm[i].type = entry->lsm[i].type; | |
39e5993d TH |
401 | nentry->lsm[i].args_p = entry->lsm[i].args_p; |
402 | /* | |
403 | * Remove the reference from entry so that the associated | |
404 | * memory will not be freed during a later call to | |
405 | * ima_lsm_free_rule(entry). | |
406 | */ | |
407 | entry->lsm[i].args_p = NULL; | |
b1694245 | 408 | |
b8867eed TH |
409 | ima_filter_rule_init(nentry->lsm[i].type, Audit_equal, |
410 | nentry->lsm[i].args_p, | |
411 | &nentry->lsm[i].rule); | |
483ec26e JK |
412 | if (!nentry->lsm[i].rule) |
413 | pr_warn("rule for LSM \'%s\' is undefined\n", | |
aa0c0227 | 414 | nentry->lsm[i].args_p); |
b1694245 JK |
415 | } |
416 | return nentry; | |
b1694245 JK |
417 | } |
418 | ||
419 | static int ima_lsm_update_rule(struct ima_rule_entry *entry) | |
420 | { | |
421 | struct ima_rule_entry *nentry; | |
422 | ||
423 | nentry = ima_lsm_copy_rule(entry); | |
424 | if (!nentry) | |
425 | return -ENOMEM; | |
426 | ||
427 | list_replace_rcu(&entry->list, &nentry->list); | |
428 | synchronize_rcu(); | |
465aee77 TH |
429 | /* |
430 | * ima_lsm_copy_rule() shallow copied all references, except for the | |
431 | * LSM references, from entry to nentry so we only want to free the LSM | |
65603435 | 432 | * references and the entry itself. All other memory references will now |
465aee77 TH |
433 | * be owned by nentry. |
434 | */ | |
b1694245 | 435 | ima_lsm_free_rule(entry); |
465aee77 | 436 | kfree(entry); |
b1694245 JK |
437 | |
438 | return 0; | |
439 | } | |
440 | ||
db2045f5 TH |
441 | static bool ima_rule_contains_lsm_cond(struct ima_rule_entry *entry) |
442 | { | |
443 | int i; | |
444 | ||
445 | for (i = 0; i < MAX_LSM_RULES; i++) | |
446 | if (entry->lsm[i].args_p) | |
447 | return true; | |
448 | ||
449 | return false; | |
450 | } | |
451 | ||
2bb930ab | 452 | /* |
38d859f9 PM |
453 | * The LSM policy can be reloaded, leaving the IMA LSM based rules referring |
454 | * to the old, stale LSM policy. Update the IMA LSM based rules to reflect | |
b1694245 | 455 | * the reloaded LSM policy. |
7163a993 MZ |
456 | */ |
457 | static void ima_lsm_update_rules(void) | |
458 | { | |
b1694245 | 459 | struct ima_rule_entry *entry, *e; |
592b24cb | 460 | int result; |
7163a993 | 461 | |
b1694245 | 462 | list_for_each_entry_safe(entry, e, &ima_policy_rules, list) { |
592b24cb | 463 | if (!ima_rule_contains_lsm_cond(entry)) |
b1694245 JK |
464 | continue; |
465 | ||
466 | result = ima_lsm_update_rule(entry); | |
467 | if (result) { | |
483ec26e | 468 | pr_err("lsm rule update error %d\n", result); |
b1694245 | 469 | return; |
7163a993 MZ |
470 | } |
471 | } | |
7163a993 MZ |
472 | } |
473 | ||
b1694245 JK |
474 | int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, |
475 | void *lsm_data) | |
476 | { | |
477 | if (event != LSM_POLICY_CHANGE) | |
478 | return NOTIFY_DONE; | |
479 | ||
480 | ima_lsm_update_rules(); | |
481 | return NOTIFY_OK; | |
482 | } | |
483 | ||
3323eec9 | 484 | /** |
2b4a2474 | 485 | * ima_match_rule_data - determine whether func_data matches the policy rule |
e9085e0a | 486 | * @rule: a pointer to a rule |
2b4a2474 | 487 | * @func_data: data to match against the measure rule data |
e9085e0a LR |
488 | * @cred: a pointer to a credentials structure for user validation |
489 | * | |
2b4a2474 | 490 | * Returns true if func_data matches one in the rule, false otherwise. |
e9085e0a | 491 | */ |
2b4a2474 TS |
492 | static bool ima_match_rule_data(struct ima_rule_entry *rule, |
493 | const char *func_data, | |
494 | const struct cred *cred) | |
e9085e0a | 495 | { |
2b4a2474 | 496 | const struct ima_rule_opt_list *opt_list = NULL; |
e9085e0a | 497 | bool matched = false; |
176377d9 | 498 | size_t i; |
e9085e0a LR |
499 | |
500 | if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid)) | |
501 | return false; | |
502 | ||
2b4a2474 TS |
503 | switch (rule->func) { |
504 | case KEY_CHECK: | |
505 | if (!rule->keyrings) | |
506 | return true; | |
507 | ||
508 | opt_list = rule->keyrings; | |
509 | break; | |
c4e43aa2 | 510 | case CRITICAL_DATA: |
47d76a48 TS |
511 | if (!rule->label) |
512 | return true; | |
513 | ||
514 | opt_list = rule->label; | |
515 | break; | |
2b4a2474 TS |
516 | default: |
517 | return false; | |
518 | } | |
e9085e0a | 519 | |
2b4a2474 | 520 | if (!func_data) |
e9085e0a LR |
521 | return false; |
522 | ||
2b4a2474 TS |
523 | for (i = 0; i < opt_list->count; i++) { |
524 | if (!strcmp(opt_list->items[i], func_data)) { | |
e9085e0a LR |
525 | matched = true; |
526 | break; | |
527 | } | |
528 | } | |
529 | ||
e9085e0a LR |
530 | return matched; |
531 | } | |
532 | ||
3323eec9 | 533 | /** |
483ec26e | 534 | * ima_match_rules - determine whether an inode matches the policy rule. |
3323eec9 | 535 | * @rule: a pointer to a rule |
a2d2329e | 536 | * @mnt_userns: user namespace of the mount the inode was found from |
3323eec9 | 537 | * @inode: a pointer to an inode |
d906c10d MG |
538 | * @cred: a pointer to a credentials structure for user validation |
539 | * @secid: the secid of the task to be validated | |
3323eec9 MZ |
540 | * @func: LIM hook identifier |
541 | * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) | |
2b4a2474 | 542 | * @func_data: func specific data, may be NULL |
3323eec9 MZ |
543 | * |
544 | * Returns true on rule match, false on failure. | |
545 | */ | |
a2d2329e CB |
546 | static bool ima_match_rules(struct ima_rule_entry *rule, |
547 | struct user_namespace *mnt_userns, | |
548 | struct inode *inode, const struct cred *cred, | |
549 | u32 secid, enum ima_hooks func, int mask, | |
2b4a2474 | 550 | const char *func_data) |
3323eec9 | 551 | { |
4af4662f | 552 | int i; |
3323eec9 | 553 | |
09b1148e DK |
554 | if ((rule->flags & IMA_FUNC) && |
555 | (rule->func != func && func != POST_SETATTR)) | |
3323eec9 | 556 | return false; |
c4e43aa2 TS |
557 | |
558 | switch (func) { | |
559 | case KEY_CHECK: | |
560 | case CRITICAL_DATA: | |
561 | return ((rule->func == func) && | |
562 | ima_match_rule_data(rule, func_data, cred)); | |
563 | default: | |
564 | break; | |
565 | } | |
566 | ||
09b1148e DK |
567 | if ((rule->flags & IMA_MASK) && |
568 | (rule->mask != mask && func != POST_SETATTR)) | |
3323eec9 | 569 | return false; |
4351c294 MZ |
570 | if ((rule->flags & IMA_INMASK) && |
571 | (!(rule->mask & mask) && func != POST_SETATTR)) | |
572 | return false; | |
3323eec9 MZ |
573 | if ((rule->flags & IMA_FSMAGIC) |
574 | && rule->fsmagic != inode->i_sb->s_magic) | |
575 | return false; | |
f1b08bbc MZ |
576 | if ((rule->flags & IMA_FSNAME) |
577 | && strcmp(rule->fsname, inode->i_sb->s_type->name)) | |
578 | return false; | |
85865c1f | 579 | if ((rule->flags & IMA_FSUUID) && |
85787090 | 580 | !uuid_equal(&rule->fsuuid, &inode->i_sb->s_uuid)) |
85865c1f | 581 | return false; |
3dd0c8d0 | 582 | if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid)) |
3323eec9 | 583 | return false; |
139069ef MZ |
584 | if (rule->flags & IMA_EUID) { |
585 | if (has_capability_noaudit(current, CAP_SETUID)) { | |
3dd0c8d0 MK |
586 | if (!rule->uid_op(cred->euid, rule->uid) |
587 | && !rule->uid_op(cred->suid, rule->uid) | |
588 | && !rule->uid_op(cred->uid, rule->uid)) | |
139069ef | 589 | return false; |
3dd0c8d0 | 590 | } else if (!rule->uid_op(cred->euid, rule->uid)) |
139069ef MZ |
591 | return false; |
592 | } | |
40224c41 CV |
593 | if ((rule->flags & IMA_GID) && !rule->gid_op(cred->gid, rule->gid)) |
594 | return false; | |
595 | if (rule->flags & IMA_EGID) { | |
596 | if (has_capability_noaudit(current, CAP_SETGID)) { | |
597 | if (!rule->gid_op(cred->egid, rule->gid) | |
598 | && !rule->gid_op(cred->sgid, rule->gid) | |
599 | && !rule->gid_op(cred->gid, rule->gid)) | |
600 | return false; | |
601 | } else if (!rule->gid_op(cred->egid, rule->gid)) | |
602 | return false; | |
603 | } | |
3dd0c8d0 | 604 | if ((rule->flags & IMA_FOWNER) && |
a2d2329e | 605 | !rule->fowner_op(i_uid_into_mnt(mnt_userns, inode), rule->fowner)) |
07f6a794 | 606 | return false; |
40224c41 CV |
607 | if ((rule->flags & IMA_FGROUP) && |
608 | !rule->fgroup_op(i_gid_into_mnt(mnt_userns, inode), rule->fgroup)) | |
609 | return false; | |
4af4662f | 610 | for (i = 0; i < MAX_LSM_RULES; i++) { |
53fc0e22 | 611 | int rc = 0; |
d906c10d | 612 | u32 osid; |
4af4662f | 613 | |
483ec26e JK |
614 | if (!rule->lsm[i].rule) { |
615 | if (!rule->lsm[i].args_p) | |
616 | continue; | |
617 | else | |
618 | return false; | |
619 | } | |
4af4662f MZ |
620 | switch (i) { |
621 | case LSM_OBJ_USER: | |
622 | case LSM_OBJ_ROLE: | |
623 | case LSM_OBJ_TYPE: | |
624 | security_inode_getsecid(inode, &osid); | |
b8867eed TH |
625 | rc = ima_filter_rule_match(osid, rule->lsm[i].type, |
626 | Audit_equal, | |
627 | rule->lsm[i].rule); | |
4af4662f MZ |
628 | break; |
629 | case LSM_SUBJ_USER: | |
630 | case LSM_SUBJ_ROLE: | |
631 | case LSM_SUBJ_TYPE: | |
b8867eed TH |
632 | rc = ima_filter_rule_match(secid, rule->lsm[i].type, |
633 | Audit_equal, | |
634 | rule->lsm[i].rule); | |
28073eb0 | 635 | break; |
4af4662f MZ |
636 | default: |
637 | break; | |
638 | } | |
639 | if (!rc) | |
640 | return false; | |
641 | } | |
3323eec9 MZ |
642 | return true; |
643 | } | |
644 | ||
d79d72e0 MZ |
645 | /* |
646 | * In addition to knowing that we need to appraise the file in general, | |
5a73fcfa | 647 | * we need to differentiate between calling hooks, for hook specific rules. |
d79d72e0 | 648 | */ |
4ad87a3d | 649 | static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) |
d79d72e0 | 650 | { |
5a73fcfa MZ |
651 | if (!(rule->flags & IMA_FUNC)) |
652 | return IMA_FILE_APPRAISE; | |
653 | ||
2bb930ab | 654 | switch (func) { |
d79d72e0 MZ |
655 | case MMAP_CHECK: |
656 | return IMA_MMAP_APPRAISE; | |
657 | case BPRM_CHECK: | |
658 | return IMA_BPRM_APPRAISE; | |
d906c10d MG |
659 | case CREDS_CHECK: |
660 | return IMA_CREDS_APPRAISE; | |
d79d72e0 | 661 | case FILE_CHECK: |
c6af8efe | 662 | case POST_SETATTR: |
d79d72e0 | 663 | return IMA_FILE_APPRAISE; |
c6af8efe MZ |
664 | case MODULE_CHECK ... MAX_CHECK - 1: |
665 | default: | |
666 | return IMA_READ_APPRAISE; | |
d79d72e0 MZ |
667 | } |
668 | } | |
669 | ||
3323eec9 MZ |
670 | /** |
671 | * ima_match_policy - decision based on LSM and other conditions | |
a2d2329e | 672 | * @mnt_userns: user namespace of the mount the inode was found from |
3323eec9 | 673 | * @inode: pointer to an inode for which the policy decision is being made |
d906c10d MG |
674 | * @cred: pointer to a credentials structure for which the policy decision is |
675 | * being made | |
676 | * @secid: LSM secid of the task to be validated | |
3323eec9 MZ |
677 | * @func: IMA hook identifier |
678 | * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) | |
725de7fa | 679 | * @pcr: set the pcr to extend |
19453ce0 | 680 | * @template_desc: the template that should be used for this rule |
2b4a2474 | 681 | * @func_data: func specific data, may be NULL |
1624dc00 | 682 | * @allowed_algos: allowlist of hash algorithms for the IMA xattr |
3323eec9 MZ |
683 | * |
684 | * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) | |
685 | * conditions. | |
686 | * | |
38d859f9 PM |
687 | * Since the IMA policy may be updated multiple times we need to lock the |
688 | * list when walking it. Reads are many orders of magnitude more numerous | |
689 | * than writes so ima_match_policy() is classical RCU candidate. | |
3323eec9 | 690 | */ |
a2d2329e CB |
691 | int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, |
692 | const struct cred *cred, u32 secid, enum ima_hooks func, | |
693 | int mask, int flags, int *pcr, | |
e9085e0a | 694 | struct ima_template_desc **template_desc, |
1624dc00 | 695 | const char *func_data, unsigned int *allowed_algos) |
3323eec9 | 696 | { |
07f6a794 | 697 | struct ima_rule_entry *entry; |
2fe5d6de | 698 | int action = 0, actmask = flags | (flags << 1); |
eb0782bb | 699 | struct list_head *ima_rules_tmp; |
3323eec9 | 700 | |
dea87d08 | 701 | if (template_desc && !*template_desc) |
b36f281f MZ |
702 | *template_desc = ima_template_desc_current(); |
703 | ||
38d859f9 | 704 | rcu_read_lock(); |
eb0782bb | 705 | ima_rules_tmp = rcu_dereference(ima_rules); |
706 | list_for_each_entry_rcu(entry, ima_rules_tmp, list) { | |
3323eec9 | 707 | |
2fe5d6de MZ |
708 | if (!(entry->action & actmask)) |
709 | continue; | |
710 | ||
a2d2329e | 711 | if (!ima_match_rules(entry, mnt_userns, inode, cred, secid, |
7d6beb71 | 712 | func, mask, func_data)) |
2fe5d6de | 713 | continue; |
3323eec9 | 714 | |
aae6ccbd | 715 | action |= entry->flags & IMA_NONACTION_FLAGS; |
0e5a247c | 716 | |
45e2472e | 717 | action |= entry->action & IMA_DO_MASK; |
da1b0029 | 718 | if (entry->action & IMA_APPRAISE) { |
5a73fcfa | 719 | action |= get_subaction(entry, func); |
a9a4935d | 720 | action &= ~IMA_HASH; |
9e67028e MZ |
721 | if (ima_fail_unverifiable_sigs) |
722 | action |= IMA_FAIL_UNVERIFIABLE_SIGS; | |
d79d72e0 | 723 | |
1624dc00 TS |
724 | if (allowed_algos && |
725 | entry->flags & IMA_VALIDATE_ALGOS) | |
726 | *allowed_algos = entry->allowed_algos; | |
727 | } | |
b36f281f | 728 | |
45e2472e DK |
729 | if (entry->action & IMA_DO_MASK) |
730 | actmask &= ~(entry->action | entry->action << 1); | |
731 | else | |
732 | actmask &= ~(entry->action | entry->action >> 1); | |
3323eec9 | 733 | |
725de7fa ER |
734 | if ((pcr) && (entry->flags & IMA_PCR)) |
735 | *pcr = entry->pcr; | |
736 | ||
19453ce0 MG |
737 | if (template_desc && entry->template) |
738 | *template_desc = entry->template; | |
19453ce0 | 739 | |
2fe5d6de MZ |
740 | if (!actmask) |
741 | break; | |
3323eec9 | 742 | } |
38d859f9 | 743 | rcu_read_unlock(); |
2fe5d6de MZ |
744 | |
745 | return action; | |
3323eec9 MZ |
746 | } |
747 | ||
4f2946aa TS |
748 | /** |
749 | * ima_update_policy_flags() - Update global IMA variables | |
750 | * | |
751 | * Update ima_policy_flag and ima_setxattr_allowed_hash_algorithms | |
752 | * based on the currently loaded policy. | |
753 | * | |
754 | * With ima_policy_flag, the decision to short circuit out of a function | |
755 | * or not call the function in the first place can be made earlier. | |
756 | * | |
757 | * With ima_setxattr_allowed_hash_algorithms, the policy can restrict the | |
758 | * set of hash algorithms accepted when updating the security.ima xattr of | |
759 | * a file. | |
760 | * | |
761 | * Context: called after a policy update and at system initialization. | |
a756024e | 762 | */ |
4f2946aa | 763 | void ima_update_policy_flags(void) |
a756024e RS |
764 | { |
765 | struct ima_rule_entry *entry; | |
4f2946aa | 766 | int new_policy_flag = 0; |
eb0782bb | 767 | struct list_head *ima_rules_tmp; |
a756024e | 768 | |
4f2946aa | 769 | rcu_read_lock(); |
eb0782bb | 770 | ima_rules_tmp = rcu_dereference(ima_rules); |
771 | list_for_each_entry_rcu(entry, ima_rules_tmp, list) { | |
4f2946aa TS |
772 | /* |
773 | * SETXATTR_CHECK rules do not implement a full policy check | |
774 | * because rule checking would probably have an important | |
775 | * performance impact on setxattr(). As a consequence, only one | |
776 | * SETXATTR_CHECK can be active at a given time. | |
777 | * Because we want to preserve that property, we set out to use | |
778 | * atomic_cmpxchg. Either: | |
779 | * - the atomic was non-zero: a setxattr hash policy is | |
780 | * already enforced, we do nothing | |
781 | * - the atomic was zero: no setxattr policy was set, enable | |
782 | * the setxattr hash policy | |
783 | */ | |
784 | if (entry->func == SETXATTR_CHECK) { | |
785 | atomic_cmpxchg(&ima_setxattr_allowed_hash_algorithms, | |
786 | 0, entry->allowed_algos); | |
787 | /* SETXATTR_CHECK doesn't impact ima_policy_flag */ | |
788 | continue; | |
789 | } | |
790 | ||
a756024e | 791 | if (entry->action & IMA_DO_MASK) |
4f2946aa | 792 | new_policy_flag |= entry->action; |
a756024e | 793 | } |
4f2946aa | 794 | rcu_read_unlock(); |
a756024e | 795 | |
ef96837b | 796 | ima_appraise |= (build_ima_appraise | temp_ima_appraise); |
a756024e | 797 | if (!ima_appraise) |
4f2946aa TS |
798 | new_policy_flag &= ~IMA_APPRAISE; |
799 | ||
800 | ima_policy_flag = new_policy_flag; | |
a756024e RS |
801 | } |
802 | ||
6f0911a6 MZ |
803 | static int ima_appraise_flag(enum ima_hooks func) |
804 | { | |
805 | if (func == MODULE_CHECK) | |
806 | return IMA_APPRAISE_MODULES; | |
807 | else if (func == FIRMWARE_CHECK) | |
808 | return IMA_APPRAISE_FIRMWARE; | |
809 | else if (func == POLICY_CHECK) | |
810 | return IMA_APPRAISE_POLICY; | |
16c267aa MZ |
811 | else if (func == KEXEC_KERNEL_CHECK) |
812 | return IMA_APPRAISE_KEXEC; | |
6f0911a6 MZ |
813 | return 0; |
814 | } | |
815 | ||
c52657d9 NJ |
816 | static void add_rules(struct ima_rule_entry *entries, int count, |
817 | enum policy_rule_list policy_rule) | |
818 | { | |
819 | int i = 0; | |
820 | ||
821 | for (i = 0; i < count; i++) { | |
822 | struct ima_rule_entry *entry; | |
823 | ||
824 | if (policy_rule & IMA_DEFAULT_POLICY) | |
825 | list_add_tail(&entries[i].list, &ima_default_rules); | |
826 | ||
827 | if (policy_rule & IMA_CUSTOM_POLICY) { | |
828 | entry = kmemdup(&entries[i], sizeof(*entry), | |
829 | GFP_KERNEL); | |
830 | if (!entry) | |
831 | continue; | |
832 | ||
833 | list_add_tail(&entry->list, &ima_policy_rules); | |
834 | } | |
b59fda44 KS |
835 | if (entries[i].action == APPRAISE) { |
836 | if (entries != build_appraise_rules) | |
837 | temp_ima_appraise |= | |
838 | ima_appraise_flag(entries[i].func); | |
839 | else | |
840 | build_ima_appraise |= | |
841 | ima_appraise_flag(entries[i].func); | |
842 | } | |
c52657d9 NJ |
843 | } |
844 | } | |
845 | ||
61917062 NJ |
846 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry); |
847 | ||
848 | static int __init ima_init_arch_policy(void) | |
849 | { | |
850 | const char * const *arch_rules; | |
851 | const char * const *rules; | |
852 | int arch_entries = 0; | |
853 | int i = 0; | |
854 | ||
855 | arch_rules = arch_get_ima_policy(); | |
856 | if (!arch_rules) | |
857 | return arch_entries; | |
858 | ||
859 | /* Get number of rules */ | |
860 | for (rules = arch_rules; *rules != NULL; rules++) | |
861 | arch_entries++; | |
862 | ||
863 | arch_policy_entry = kcalloc(arch_entries + 1, | |
864 | sizeof(*arch_policy_entry), GFP_KERNEL); | |
865 | if (!arch_policy_entry) | |
866 | return 0; | |
867 | ||
868 | /* Convert each policy string rules to struct ima_rule_entry format */ | |
869 | for (rules = arch_rules, i = 0; *rules != NULL; rules++) { | |
870 | char rule[255]; | |
871 | int result; | |
872 | ||
cc4299ea | 873 | result = strscpy(rule, *rules, sizeof(rule)); |
61917062 NJ |
874 | |
875 | INIT_LIST_HEAD(&arch_policy_entry[i].list); | |
876 | result = ima_parse_rule(rule, &arch_policy_entry[i]); | |
877 | if (result) { | |
878 | pr_warn("Skipping unknown architecture policy rule: %s\n", | |
879 | rule); | |
880 | memset(&arch_policy_entry[i], 0, | |
881 | sizeof(*arch_policy_entry)); | |
882 | continue; | |
883 | } | |
884 | i++; | |
885 | } | |
886 | return i; | |
887 | } | |
888 | ||
3323eec9 MZ |
889 | /** |
890 | * ima_init_policy - initialize the default measure rules. | |
891 | * | |
61868acb | 892 | * ima_rules points to either the ima_default_rules or the new ima_policy_rules. |
3323eec9 | 893 | */ |
932995f0 | 894 | void __init ima_init_policy(void) |
3323eec9 | 895 | { |
61917062 | 896 | int build_appraise_entries, arch_entries; |
2bb930ab | 897 | |
c52657d9 NJ |
898 | /* if !ima_policy, we load NO default rules */ |
899 | if (ima_policy) | |
900 | add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules), | |
901 | IMA_DEFAULT_POLICY); | |
24fd03c8 MZ |
902 | |
903 | switch (ima_policy) { | |
904 | case ORIGINAL_TCB: | |
c52657d9 NJ |
905 | add_rules(original_measurement_rules, |
906 | ARRAY_SIZE(original_measurement_rules), | |
907 | IMA_DEFAULT_POLICY); | |
24fd03c8 MZ |
908 | break; |
909 | case DEFAULT_TCB: | |
c52657d9 NJ |
910 | add_rules(default_measurement_rules, |
911 | ARRAY_SIZE(default_measurement_rules), | |
912 | IMA_DEFAULT_POLICY); | |
28073eb0 | 913 | break; |
24fd03c8 MZ |
914 | default: |
915 | break; | |
916 | } | |
5577857f | 917 | |
61917062 NJ |
918 | /* |
919 | * Based on runtime secure boot flags, insert arch specific measurement | |
920 | * and appraise rules requiring file signatures for both the initial | |
921 | * and custom policies, prior to other appraise rules. | |
922 | * (Highest priority) | |
923 | */ | |
924 | arch_entries = ima_init_arch_policy(); | |
925 | if (!arch_entries) | |
926 | pr_info("No architecture policies found\n"); | |
927 | else | |
928 | add_rules(arch_policy_entry, arch_entries, | |
929 | IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); | |
930 | ||
503ceaef | 931 | /* |
ef96837b | 932 | * Insert the builtin "secure_boot" policy rules requiring file |
61917062 | 933 | * signatures, prior to other appraise rules. |
503ceaef | 934 | */ |
c52657d9 NJ |
935 | if (ima_use_secure_boot) |
936 | add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules), | |
937 | IMA_DEFAULT_POLICY); | |
503ceaef | 938 | |
ef96837b MZ |
939 | /* |
940 | * Insert the build time appraise rules requiring file signatures | |
941 | * for both the initial and custom policies, prior to other appraise | |
c52657d9 NJ |
942 | * rules. As the secure boot rules includes all of the build time |
943 | * rules, include either one or the other set of rules, but not both. | |
ef96837b | 944 | */ |
c52657d9 NJ |
945 | build_appraise_entries = ARRAY_SIZE(build_appraise_rules); |
946 | if (build_appraise_entries) { | |
947 | if (ima_use_secure_boot) | |
948 | add_rules(build_appraise_rules, build_appraise_entries, | |
949 | IMA_CUSTOM_POLICY); | |
950 | else | |
951 | add_rules(build_appraise_rules, build_appraise_entries, | |
952 | IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); | |
ef96837b MZ |
953 | } |
954 | ||
c52657d9 NJ |
955 | if (ima_use_appraise_tcb) |
956 | add_rules(default_appraise_rules, | |
957 | ARRAY_SIZE(default_appraise_rules), | |
958 | IMA_DEFAULT_POLICY); | |
07f6a794 | 959 | |
03cee168 LR |
960 | if (ima_use_critical_data) |
961 | add_rules(critical_data_rules, | |
962 | ARRAY_SIZE(critical_data_rules), | |
963 | IMA_DEFAULT_POLICY); | |
964 | ||
4f2946aa TS |
965 | atomic_set(&ima_setxattr_allowed_hash_algorithms, 0); |
966 | ||
967 | ima_update_policy_flags(); | |
3323eec9 | 968 | } |
4af4662f | 969 | |
0112721d | 970 | /* Make sure we have a valid policy, at least containing some rules. */ |
c75d8e96 | 971 | int ima_check_policy(void) |
0112721d SL |
972 | { |
973 | if (list_empty(&ima_temp_rules)) | |
974 | return -EINVAL; | |
975 | return 0; | |
976 | } | |
977 | ||
4af4662f MZ |
978 | /** |
979 | * ima_update_policy - update default_rules with new measure rules | |
980 | * | |
981 | * Called on file .release to update the default rules with a complete new | |
38d859f9 PM |
982 | * policy. What we do here is to splice ima_policy_rules and ima_temp_rules so |
983 | * they make a queue. The policy may be updated multiple times and this is the | |
984 | * RCU updater. | |
985 | * | |
986 | * Policy rules are never deleted so ima_policy_flag gets zeroed only once when | |
987 | * we switch from the default policy to user defined. | |
4af4662f MZ |
988 | */ |
989 | void ima_update_policy(void) | |
990 | { | |
53b626f9 | 991 | struct list_head *policy = &ima_policy_rules; |
38d859f9 | 992 | |
53b626f9 | 993 | list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu); |
38d859f9 | 994 | |
eb0782bb | 995 | if (ima_rules != (struct list_head __rcu *)policy) { |
38d859f9 | 996 | ima_policy_flag = 0; |
61917062 | 997 | |
eb0782bb | 998 | rcu_assign_pointer(ima_rules, policy); |
61917062 NJ |
999 | /* |
1000 | * IMA architecture specific policy rules are specified | |
1001 | * as strings and converted to an array of ima_entry_rules | |
1002 | * on boot. After loading a custom policy, free the | |
1003 | * architecture specific rules stored as an array. | |
1004 | */ | |
1005 | kfree(arch_policy_entry); | |
38d859f9 | 1006 | } |
4f2946aa | 1007 | ima_update_policy_flags(); |
450d0fd5 LR |
1008 | |
1009 | /* Custom IMA policy has been loaded */ | |
1010 | ima_process_queued_keys(); | |
4af4662f MZ |
1011 | } |
1012 | ||
1a9430db | 1013 | /* Keep the enumeration in sync with the policy_tokens! */ |
40224c41 | 1014 | enum policy_opt { |
1a9430db | 1015 | Opt_measure, Opt_dont_measure, |
07f6a794 | 1016 | Opt_appraise, Opt_dont_appraise, |
da1b0029 | 1017 | Opt_audit, Opt_hash, Opt_dont_hash, |
4af4662f MZ |
1018 | Opt_obj_user, Opt_obj_role, Opt_obj_type, |
1019 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | |
40224c41 CV |
1020 | Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname, Opt_fsuuid, |
1021 | Opt_uid_eq, Opt_euid_eq, Opt_gid_eq, Opt_egid_eq, | |
1022 | Opt_fowner_eq, Opt_fgroup_eq, | |
1023 | Opt_uid_gt, Opt_euid_gt, Opt_gid_gt, Opt_egid_gt, | |
1024 | Opt_fowner_gt, Opt_fgroup_gt, | |
1025 | Opt_uid_lt, Opt_euid_lt, Opt_gid_lt, Opt_egid_lt, | |
1026 | Opt_fowner_lt, Opt_fgroup_lt, | |
583a80ae | 1027 | Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos, |
2b60c0ec | 1028 | Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings, |
47d76a48 | 1029 | Opt_label, Opt_err |
4af4662f MZ |
1030 | }; |
1031 | ||
1a9430db | 1032 | static const match_table_t policy_tokens = { |
4af4662f MZ |
1033 | {Opt_measure, "measure"}, |
1034 | {Opt_dont_measure, "dont_measure"}, | |
07f6a794 MZ |
1035 | {Opt_appraise, "appraise"}, |
1036 | {Opt_dont_appraise, "dont_appraise"}, | |
e7c568e0 | 1037 | {Opt_audit, "audit"}, |
da1b0029 MZ |
1038 | {Opt_hash, "hash"}, |
1039 | {Opt_dont_hash, "dont_hash"}, | |
4af4662f MZ |
1040 | {Opt_obj_user, "obj_user=%s"}, |
1041 | {Opt_obj_role, "obj_role=%s"}, | |
1042 | {Opt_obj_type, "obj_type=%s"}, | |
1043 | {Opt_subj_user, "subj_user=%s"}, | |
1044 | {Opt_subj_role, "subj_role=%s"}, | |
1045 | {Opt_subj_type, "subj_type=%s"}, | |
1046 | {Opt_func, "func=%s"}, | |
1047 | {Opt_mask, "mask=%s"}, | |
1048 | {Opt_fsmagic, "fsmagic=%s"}, | |
f1b08bbc | 1049 | {Opt_fsname, "fsname=%s"}, |
85865c1f | 1050 | {Opt_fsuuid, "fsuuid=%s"}, |
3dd0c8d0 MK |
1051 | {Opt_uid_eq, "uid=%s"}, |
1052 | {Opt_euid_eq, "euid=%s"}, | |
40224c41 CV |
1053 | {Opt_gid_eq, "gid=%s"}, |
1054 | {Opt_egid_eq, "egid=%s"}, | |
3dd0c8d0 | 1055 | {Opt_fowner_eq, "fowner=%s"}, |
40224c41 | 1056 | {Opt_fgroup_eq, "fgroup=%s"}, |
3dd0c8d0 MK |
1057 | {Opt_uid_gt, "uid>%s"}, |
1058 | {Opt_euid_gt, "euid>%s"}, | |
40224c41 CV |
1059 | {Opt_gid_gt, "gid>%s"}, |
1060 | {Opt_egid_gt, "egid>%s"}, | |
3dd0c8d0 | 1061 | {Opt_fowner_gt, "fowner>%s"}, |
40224c41 | 1062 | {Opt_fgroup_gt, "fgroup>%s"}, |
3dd0c8d0 MK |
1063 | {Opt_uid_lt, "uid<%s"}, |
1064 | {Opt_euid_lt, "euid<%s"}, | |
40224c41 CV |
1065 | {Opt_gid_lt, "gid<%s"}, |
1066 | {Opt_egid_lt, "egid<%s"}, | |
3dd0c8d0 | 1067 | {Opt_fowner_lt, "fowner<%s"}, |
40224c41 | 1068 | {Opt_fgroup_lt, "fgroup<%s"}, |
0e5a247c | 1069 | {Opt_appraise_type, "appraise_type=%s"}, |
273df864 | 1070 | {Opt_appraise_flag, "appraise_flag=%s"}, |
583a80ae | 1071 | {Opt_appraise_algos, "appraise_algos=%s"}, |
f9b2a735 | 1072 | {Opt_permit_directio, "permit_directio"}, |
0260643c | 1073 | {Opt_pcr, "pcr=%s"}, |
19453ce0 | 1074 | {Opt_template, "template=%s"}, |
2b60c0ec | 1075 | {Opt_keyrings, "keyrings=%s"}, |
47d76a48 | 1076 | {Opt_label, "label=%s"}, |
4af4662f MZ |
1077 | {Opt_err, NULL} |
1078 | }; | |
1079 | ||
07f6a794 | 1080 | static int ima_lsm_rule_init(struct ima_rule_entry *entry, |
7163a993 | 1081 | substring_t *args, int lsm_rule, int audit_type) |
4af4662f MZ |
1082 | { |
1083 | int result; | |
1084 | ||
7b62e162 EP |
1085 | if (entry->lsm[lsm_rule].rule) |
1086 | return -EINVAL; | |
1087 | ||
7163a993 MZ |
1088 | entry->lsm[lsm_rule].args_p = match_strdup(args); |
1089 | if (!entry->lsm[lsm_rule].args_p) | |
1090 | return -ENOMEM; | |
1091 | ||
4af4662f | 1092 | entry->lsm[lsm_rule].type = audit_type; |
b8867eed TH |
1093 | result = ima_filter_rule_init(entry->lsm[lsm_rule].type, Audit_equal, |
1094 | entry->lsm[lsm_rule].args_p, | |
1095 | &entry->lsm[lsm_rule].rule); | |
7163a993 | 1096 | if (!entry->lsm[lsm_rule].rule) { |
483ec26e | 1097 | pr_warn("rule for LSM \'%s\' is undefined\n", |
aa0c0227 | 1098 | entry->lsm[lsm_rule].args_p); |
483ec26e | 1099 | |
eb0782bb | 1100 | if (ima_rules == (struct list_head __rcu *)(&ima_default_rules)) { |
483ec26e | 1101 | kfree(entry->lsm[lsm_rule].args_p); |
2bdd737c | 1102 | entry->lsm[lsm_rule].args_p = NULL; |
483ec26e JK |
1103 | result = -EINVAL; |
1104 | } else | |
1105 | result = 0; | |
7163a993 MZ |
1106 | } |
1107 | ||
4af4662f MZ |
1108 | return result; |
1109 | } | |
1110 | ||
3dd0c8d0 | 1111 | static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value, |
40224c41 | 1112 | enum policy_opt rule_operator) |
2f1506cd | 1113 | { |
2afd020a SB |
1114 | if (!ab) |
1115 | return; | |
1116 | ||
40224c41 CV |
1117 | switch (rule_operator) { |
1118 | case Opt_uid_gt: | |
1119 | case Opt_euid_gt: | |
1120 | case Opt_gid_gt: | |
1121 | case Opt_egid_gt: | |
1122 | case Opt_fowner_gt: | |
1123 | case Opt_fgroup_gt: | |
3dd0c8d0 | 1124 | audit_log_format(ab, "%s>", key); |
40224c41 CV |
1125 | break; |
1126 | case Opt_uid_lt: | |
1127 | case Opt_euid_lt: | |
1128 | case Opt_gid_lt: | |
1129 | case Opt_egid_lt: | |
1130 | case Opt_fowner_lt: | |
1131 | case Opt_fgroup_lt: | |
3dd0c8d0 | 1132 | audit_log_format(ab, "%s<", key); |
40224c41 CV |
1133 | break; |
1134 | default: | |
3dd0c8d0 | 1135 | audit_log_format(ab, "%s=", key); |
40224c41 | 1136 | } |
3d2859d5 | 1137 | audit_log_format(ab, "%s ", value); |
2f1506cd | 1138 | } |
3dd0c8d0 MK |
1139 | static void ima_log_string(struct audit_buffer *ab, char *key, char *value) |
1140 | { | |
40224c41 | 1141 | ima_log_string_op(ab, key, value, Opt_err); |
3dd0c8d0 | 1142 | } |
2f1506cd | 1143 | |
3878d505 TJB |
1144 | /* |
1145 | * Validating the appended signature included in the measurement list requires | |
1146 | * the file hash calculated without the appended signature (i.e., the 'd-modsig' | |
1147 | * field). Therefore, notify the user if they have the 'modsig' field but not | |
1148 | * the 'd-modsig' field in the template. | |
1149 | */ | |
1150 | static void check_template_modsig(const struct ima_template_desc *template) | |
1151 | { | |
1152 | #define MSG "template with 'modsig' field also needs 'd-modsig' field\n" | |
1153 | bool has_modsig, has_dmodsig; | |
1154 | static bool checked; | |
1155 | int i; | |
1156 | ||
1157 | /* We only need to notify the user once. */ | |
1158 | if (checked) | |
1159 | return; | |
1160 | ||
1161 | has_modsig = has_dmodsig = false; | |
1162 | for (i = 0; i < template->num_fields; i++) { | |
1163 | if (!strcmp(template->fields[i]->field_id, "modsig")) | |
1164 | has_modsig = true; | |
1165 | else if (!strcmp(template->fields[i]->field_id, "d-modsig")) | |
1166 | has_dmodsig = true; | |
1167 | } | |
1168 | ||
1169 | if (has_modsig && !has_dmodsig) | |
1170 | pr_notice(MSG); | |
1171 | ||
1172 | checked = true; | |
1173 | #undef MSG | |
1174 | } | |
1175 | ||
71218343 TH |
1176 | static bool ima_validate_rule(struct ima_rule_entry *entry) |
1177 | { | |
30031b0e | 1178 | /* Ensure that the action is set and is compatible with the flags */ |
71218343 TH |
1179 | if (entry->action == UNKNOWN) |
1180 | return false; | |
1181 | ||
30031b0e TH |
1182 | if (entry->action != MEASURE && entry->flags & IMA_PCR) |
1183 | return false; | |
1184 | ||
1185 | if (entry->action != APPRAISE && | |
583a80ae TS |
1186 | entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | |
1187 | IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS)) | |
30031b0e TH |
1188 | return false; |
1189 | ||
1190 | /* | |
1191 | * The IMA_FUNC bit must be set if and only if there's a valid hook | |
1192 | * function specified, and vice versa. Enforcing this property allows | |
1193 | * for the NONE case below to validate a rule without an explicit hook | |
1194 | * function. | |
1195 | */ | |
1196 | if (((entry->flags & IMA_FUNC) && entry->func == NONE) || | |
1197 | (!(entry->flags & IMA_FUNC) && entry->func != NONE)) | |
1198 | return false; | |
1199 | ||
71218343 TH |
1200 | /* |
1201 | * Ensure that the hook function is compatible with the other | |
1202 | * components of the rule | |
1203 | */ | |
1204 | switch (entry->func) { | |
1205 | case NONE: | |
1206 | case FILE_CHECK: | |
1207 | case MMAP_CHECK: | |
1208 | case BPRM_CHECK: | |
1209 | case CREDS_CHECK: | |
1210 | case POST_SETATTR: | |
71218343 | 1211 | case FIRMWARE_CHECK: |
30031b0e TH |
1212 | case POLICY_CHECK: |
1213 | if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | | |
1214 | IMA_UID | IMA_FOWNER | IMA_FSUUID | | |
1215 | IMA_INMASK | IMA_EUID | IMA_PCR | | |
40224c41 CV |
1216 | IMA_FSNAME | IMA_GID | IMA_EGID | |
1217 | IMA_FGROUP | IMA_DIGSIG_REQUIRED | | |
583a80ae | 1218 | IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS)) |
30031b0e TH |
1219 | return false; |
1220 | ||
1221 | break; | |
1222 | case MODULE_CHECK: | |
71218343 TH |
1223 | case KEXEC_KERNEL_CHECK: |
1224 | case KEXEC_INITRAMFS_CHECK: | |
30031b0e TH |
1225 | if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | |
1226 | IMA_UID | IMA_FOWNER | IMA_FSUUID | | |
1227 | IMA_INMASK | IMA_EUID | IMA_PCR | | |
40224c41 CV |
1228 | IMA_FSNAME | IMA_GID | IMA_EGID | |
1229 | IMA_FGROUP | IMA_DIGSIG_REQUIRED | | |
30031b0e | 1230 | IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED | |
583a80ae | 1231 | IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS)) |
30031b0e TH |
1232 | return false; |
1233 | ||
71218343 TH |
1234 | break; |
1235 | case KEXEC_CMDLINE: | |
db2045f5 TH |
1236 | if (entry->action & ~(MEASURE | DONT_MEASURE)) |
1237 | return false; | |
1238 | ||
4834177e TH |
1239 | if (entry->flags & ~(IMA_FUNC | IMA_FSMAGIC | IMA_UID | |
1240 | IMA_FOWNER | IMA_FSUUID | IMA_EUID | | |
40224c41 CV |
1241 | IMA_PCR | IMA_FSNAME | IMA_GID | IMA_EGID | |
1242 | IMA_FGROUP)) | |
db2045f5 TH |
1243 | return false; |
1244 | ||
1245 | break; | |
71218343 TH |
1246 | case KEY_CHECK: |
1247 | if (entry->action & ~(MEASURE | DONT_MEASURE)) | |
1248 | return false; | |
1249 | ||
40224c41 | 1250 | if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR | |
eb624fe2 TH |
1251 | IMA_KEYRINGS)) |
1252 | return false; | |
1253 | ||
1254 | if (ima_rule_contains_lsm_cond(entry)) | |
1255 | return false; | |
1256 | ||
c4e43aa2 TS |
1257 | break; |
1258 | case CRITICAL_DATA: | |
1259 | if (entry->action & ~(MEASURE | DONT_MEASURE)) | |
1260 | return false; | |
1261 | ||
40224c41 | 1262 | if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR | |
47d76a48 | 1263 | IMA_LABEL)) |
c4e43aa2 TS |
1264 | return false; |
1265 | ||
1266 | if (ima_rule_contains_lsm_cond(entry)) | |
1267 | return false; | |
1268 | ||
4f2946aa TS |
1269 | break; |
1270 | case SETXATTR_CHECK: | |
1271 | /* any action other than APPRAISE is unsupported */ | |
1272 | if (entry->action != APPRAISE) | |
1273 | return false; | |
1274 | ||
1275 | /* SETXATTR_CHECK requires an appraise_algos parameter */ | |
1276 | if (!(entry->flags & IMA_VALIDATE_ALGOS)) | |
1277 | return false; | |
1278 | ||
1279 | /* | |
1280 | * full policies are not supported, they would have too | |
1281 | * much of a performance impact | |
1282 | */ | |
1283 | if (entry->flags & ~(IMA_FUNC | IMA_VALIDATE_ALGOS)) | |
1284 | return false; | |
1285 | ||
71218343 TH |
1286 | break; |
1287 | default: | |
1288 | return false; | |
1289 | } | |
1290 | ||
5f3e9265 TH |
1291 | /* Ensure that combinations of flags are compatible with each other */ |
1292 | if (entry->flags & IMA_CHECK_BLACKLIST && | |
1293 | !(entry->flags & IMA_MODSIG_ALLOWED)) | |
1294 | return false; | |
1295 | ||
71218343 TH |
1296 | return true; |
1297 | } | |
1298 | ||
583a80ae TS |
1299 | static unsigned int ima_parse_appraise_algos(char *arg) |
1300 | { | |
1301 | unsigned int res = 0; | |
1302 | int idx; | |
1303 | char *token; | |
1304 | ||
1305 | while ((token = strsep(&arg, ",")) != NULL) { | |
1306 | idx = match_string(hash_algo_name, HASH_ALGO__LAST, token); | |
1307 | ||
1308 | if (idx < 0) { | |
1309 | pr_err("unknown hash algorithm \"%s\"", | |
1310 | token); | |
1311 | return 0; | |
1312 | } | |
1313 | ||
8ecd39cb TS |
1314 | if (!crypto_has_alg(hash_algo_name[idx], 0, 0)) { |
1315 | pr_err("unavailable hash algorithm \"%s\", check your kernel configuration", | |
1316 | token); | |
1317 | return 0; | |
1318 | } | |
1319 | ||
583a80ae TS |
1320 | /* Add the hash algorithm to the 'allowed' bitfield */ |
1321 | res |= (1U << idx); | |
1322 | } | |
1323 | ||
1324 | return res; | |
1325 | } | |
1326 | ||
07f6a794 | 1327 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) |
4af4662f MZ |
1328 | { |
1329 | struct audit_buffer *ab; | |
4351c294 | 1330 | char *from; |
4af4662f | 1331 | char *p; |
40224c41 | 1332 | bool eid_token; /* either euid or egid */ |
19453ce0 | 1333 | struct ima_template_desc *template_desc; |
4af4662f MZ |
1334 | int result = 0; |
1335 | ||
dba31ee7 SB |
1336 | ab = integrity_audit_log_start(audit_context(), GFP_KERNEL, |
1337 | AUDIT_INTEGRITY_POLICY_RULE); | |
4af4662f | 1338 | |
8b94eea4 | 1339 | entry->uid = INVALID_UID; |
40224c41 | 1340 | entry->gid = INVALID_GID; |
88265322 | 1341 | entry->fowner = INVALID_UID; |
40224c41 | 1342 | entry->fgroup = INVALID_GID; |
3dd0c8d0 | 1343 | entry->uid_op = &uid_eq; |
40224c41 | 1344 | entry->gid_op = &gid_eq; |
3dd0c8d0 | 1345 | entry->fowner_op = &uid_eq; |
40224c41 | 1346 | entry->fgroup_op = &gid_eq; |
b9035b1f | 1347 | entry->action = UNKNOWN; |
28ef4002 | 1348 | while ((p = strsep(&rule, " \t")) != NULL) { |
4af4662f MZ |
1349 | substring_t args[MAX_OPT_ARGS]; |
1350 | int token; | |
1351 | unsigned long lnum; | |
1352 | ||
1353 | if (result < 0) | |
1354 | break; | |
28ef4002 EP |
1355 | if ((*p == '\0') || (*p == ' ') || (*p == '\t')) |
1356 | continue; | |
4af4662f MZ |
1357 | token = match_token(p, policy_tokens, args); |
1358 | switch (token) { | |
1359 | case Opt_measure: | |
2f1506cd | 1360 | ima_log_string(ab, "action", "measure"); |
7b62e162 EP |
1361 | |
1362 | if (entry->action != UNKNOWN) | |
1363 | result = -EINVAL; | |
1364 | ||
4af4662f MZ |
1365 | entry->action = MEASURE; |
1366 | break; | |
1367 | case Opt_dont_measure: | |
2f1506cd | 1368 | ima_log_string(ab, "action", "dont_measure"); |
7b62e162 EP |
1369 | |
1370 | if (entry->action != UNKNOWN) | |
1371 | result = -EINVAL; | |
1372 | ||
4af4662f MZ |
1373 | entry->action = DONT_MEASURE; |
1374 | break; | |
07f6a794 MZ |
1375 | case Opt_appraise: |
1376 | ima_log_string(ab, "action", "appraise"); | |
1377 | ||
1378 | if (entry->action != UNKNOWN) | |
1379 | result = -EINVAL; | |
1380 | ||
1381 | entry->action = APPRAISE; | |
1382 | break; | |
1383 | case Opt_dont_appraise: | |
1384 | ima_log_string(ab, "action", "dont_appraise"); | |
1385 | ||
1386 | if (entry->action != UNKNOWN) | |
1387 | result = -EINVAL; | |
1388 | ||
1389 | entry->action = DONT_APPRAISE; | |
1390 | break; | |
e7c568e0 PM |
1391 | case Opt_audit: |
1392 | ima_log_string(ab, "action", "audit"); | |
1393 | ||
1394 | if (entry->action != UNKNOWN) | |
1395 | result = -EINVAL; | |
1396 | ||
1397 | entry->action = AUDIT; | |
1398 | break; | |
da1b0029 MZ |
1399 | case Opt_hash: |
1400 | ima_log_string(ab, "action", "hash"); | |
1401 | ||
1402 | if (entry->action != UNKNOWN) | |
1403 | result = -EINVAL; | |
1404 | ||
1405 | entry->action = HASH; | |
1406 | break; | |
1407 | case Opt_dont_hash: | |
1408 | ima_log_string(ab, "action", "dont_hash"); | |
1409 | ||
1410 | if (entry->action != UNKNOWN) | |
1411 | result = -EINVAL; | |
1412 | ||
1413 | entry->action = DONT_HASH; | |
1414 | break; | |
4af4662f | 1415 | case Opt_func: |
2f1506cd | 1416 | ima_log_string(ab, "func", args[0].from); |
7b62e162 EP |
1417 | |
1418 | if (entry->func) | |
07f6a794 | 1419 | result = -EINVAL; |
7b62e162 | 1420 | |
1e93d005 MZ |
1421 | if (strcmp(args[0].from, "FILE_CHECK") == 0) |
1422 | entry->func = FILE_CHECK; | |
1423 | /* PATH_CHECK is for backwards compat */ | |
1424 | else if (strcmp(args[0].from, "PATH_CHECK") == 0) | |
1425 | entry->func = FILE_CHECK; | |
fdf90729 MZ |
1426 | else if (strcmp(args[0].from, "MODULE_CHECK") == 0) |
1427 | entry->func = MODULE_CHECK; | |
5a9196d7 MZ |
1428 | else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0) |
1429 | entry->func = FIRMWARE_CHECK; | |
16cac49f MZ |
1430 | else if ((strcmp(args[0].from, "FILE_MMAP") == 0) |
1431 | || (strcmp(args[0].from, "MMAP_CHECK") == 0)) | |
1432 | entry->func = MMAP_CHECK; | |
4af4662f MZ |
1433 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) |
1434 | entry->func = BPRM_CHECK; | |
d906c10d MG |
1435 | else if (strcmp(args[0].from, "CREDS_CHECK") == 0) |
1436 | entry->func = CREDS_CHECK; | |
d9ddf077 MZ |
1437 | else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") == |
1438 | 0) | |
1439 | entry->func = KEXEC_KERNEL_CHECK; | |
1440 | else if (strcmp(args[0].from, "KEXEC_INITRAMFS_CHECK") | |
1441 | == 0) | |
1442 | entry->func = KEXEC_INITRAMFS_CHECK; | |
19f8a847 MZ |
1443 | else if (strcmp(args[0].from, "POLICY_CHECK") == 0) |
1444 | entry->func = POLICY_CHECK; | |
b0935123 PS |
1445 | else if (strcmp(args[0].from, "KEXEC_CMDLINE") == 0) |
1446 | entry->func = KEXEC_CMDLINE; | |
48ce1ddc TH |
1447 | else if (IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) && |
1448 | strcmp(args[0].from, "KEY_CHECK") == 0) | |
5808611c | 1449 | entry->func = KEY_CHECK; |
c4e43aa2 TS |
1450 | else if (strcmp(args[0].from, "CRITICAL_DATA") == 0) |
1451 | entry->func = CRITICAL_DATA; | |
4f2946aa TS |
1452 | else if (strcmp(args[0].from, "SETXATTR_CHECK") == 0) |
1453 | entry->func = SETXATTR_CHECK; | |
4af4662f MZ |
1454 | else |
1455 | result = -EINVAL; | |
1456 | if (!result) | |
1457 | entry->flags |= IMA_FUNC; | |
1458 | break; | |
1459 | case Opt_mask: | |
2f1506cd | 1460 | ima_log_string(ab, "mask", args[0].from); |
7b62e162 EP |
1461 | |
1462 | if (entry->mask) | |
1463 | result = -EINVAL; | |
1464 | ||
4351c294 MZ |
1465 | from = args[0].from; |
1466 | if (*from == '^') | |
1467 | from++; | |
1468 | ||
1469 | if ((strcmp(from, "MAY_EXEC")) == 0) | |
4af4662f | 1470 | entry->mask = MAY_EXEC; |
4351c294 | 1471 | else if (strcmp(from, "MAY_WRITE") == 0) |
4af4662f | 1472 | entry->mask = MAY_WRITE; |
4351c294 | 1473 | else if (strcmp(from, "MAY_READ") == 0) |
4af4662f | 1474 | entry->mask = MAY_READ; |
4351c294 | 1475 | else if (strcmp(from, "MAY_APPEND") == 0) |
4af4662f MZ |
1476 | entry->mask = MAY_APPEND; |
1477 | else | |
1478 | result = -EINVAL; | |
1479 | if (!result) | |
4351c294 MZ |
1480 | entry->flags |= (*args[0].from == '^') |
1481 | ? IMA_INMASK : IMA_MASK; | |
4af4662f MZ |
1482 | break; |
1483 | case Opt_fsmagic: | |
2f1506cd | 1484 | ima_log_string(ab, "fsmagic", args[0].from); |
7b62e162 EP |
1485 | |
1486 | if (entry->fsmagic) { | |
1487 | result = -EINVAL; | |
1488 | break; | |
1489 | } | |
1490 | ||
2bb930ab | 1491 | result = kstrtoul(args[0].from, 16, &entry->fsmagic); |
4af4662f MZ |
1492 | if (!result) |
1493 | entry->flags |= IMA_FSMAGIC; | |
1494 | break; | |
f1b08bbc MZ |
1495 | case Opt_fsname: |
1496 | ima_log_string(ab, "fsname", args[0].from); | |
1497 | ||
1498 | entry->fsname = kstrdup(args[0].from, GFP_KERNEL); | |
1499 | if (!entry->fsname) { | |
1500 | result = -ENOMEM; | |
1501 | break; | |
1502 | } | |
1503 | result = 0; | |
1504 | entry->flags |= IMA_FSNAME; | |
1505 | break; | |
2b60c0ec LR |
1506 | case Opt_keyrings: |
1507 | ima_log_string(ab, "keyrings", args[0].from); | |
1508 | ||
48ce1ddc TH |
1509 | if (!IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) || |
1510 | entry->keyrings) { | |
2b60c0ec LR |
1511 | result = -EINVAL; |
1512 | break; | |
1513 | } | |
5c7bac9f | 1514 | |
176377d9 TH |
1515 | entry->keyrings = ima_alloc_rule_opt_list(args); |
1516 | if (IS_ERR(entry->keyrings)) { | |
1517 | result = PTR_ERR(entry->keyrings); | |
1518 | entry->keyrings = NULL; | |
2b60c0ec LR |
1519 | break; |
1520 | } | |
176377d9 | 1521 | |
2b60c0ec LR |
1522 | entry->flags |= IMA_KEYRINGS; |
1523 | break; | |
47d76a48 TS |
1524 | case Opt_label: |
1525 | ima_log_string(ab, "label", args[0].from); | |
1526 | ||
1527 | if (entry->label) { | |
1528 | result = -EINVAL; | |
1529 | break; | |
1530 | } | |
1531 | ||
1532 | entry->label = ima_alloc_rule_opt_list(args); | |
1533 | if (IS_ERR(entry->label)) { | |
1534 | result = PTR_ERR(entry->label); | |
1535 | entry->label = NULL; | |
1536 | break; | |
1537 | } | |
1538 | ||
1539 | entry->flags |= IMA_LABEL; | |
1540 | break; | |
85865c1f DK |
1541 | case Opt_fsuuid: |
1542 | ima_log_string(ab, "fsuuid", args[0].from); | |
1543 | ||
36447456 | 1544 | if (!uuid_is_null(&entry->fsuuid)) { |
85865c1f DK |
1545 | result = -EINVAL; |
1546 | break; | |
1547 | } | |
1548 | ||
787d8c53 | 1549 | result = uuid_parse(args[0].from, &entry->fsuuid); |
446d64e3 MZ |
1550 | if (!result) |
1551 | entry->flags |= IMA_FSUUID; | |
85865c1f | 1552 | break; |
3dd0c8d0 MK |
1553 | case Opt_uid_gt: |
1554 | case Opt_euid_gt: | |
1555 | entry->uid_op = &uid_gt; | |
df561f66 | 1556 | fallthrough; |
3dd0c8d0 MK |
1557 | case Opt_uid_lt: |
1558 | case Opt_euid_lt: | |
1559 | if ((token == Opt_uid_lt) || (token == Opt_euid_lt)) | |
1560 | entry->uid_op = &uid_lt; | |
df561f66 | 1561 | fallthrough; |
3dd0c8d0 MK |
1562 | case Opt_uid_eq: |
1563 | case Opt_euid_eq: | |
40224c41 CV |
1564 | eid_token = (token == Opt_euid_eq) || |
1565 | (token == Opt_euid_gt) || | |
1566 | (token == Opt_euid_lt); | |
3dd0c8d0 | 1567 | |
40224c41 CV |
1568 | ima_log_string_op(ab, eid_token ? "euid" : "uid", |
1569 | args[0].from, token); | |
7b62e162 | 1570 | |
8b94eea4 | 1571 | if (uid_valid(entry->uid)) { |
7b62e162 EP |
1572 | result = -EINVAL; |
1573 | break; | |
1574 | } | |
1575 | ||
29707b20 | 1576 | result = kstrtoul(args[0].from, 10, &lnum); |
4af4662f | 1577 | if (!result) { |
139069ef MZ |
1578 | entry->uid = make_kuid(current_user_ns(), |
1579 | (uid_t) lnum); | |
1580 | if (!uid_valid(entry->uid) || | |
1581 | (uid_t)lnum != lnum) | |
4af4662f MZ |
1582 | result = -EINVAL; |
1583 | else | |
40224c41 CV |
1584 | entry->flags |= eid_token |
1585 | ? IMA_EUID : IMA_UID; | |
1586 | } | |
1587 | break; | |
1588 | case Opt_gid_gt: | |
1589 | case Opt_egid_gt: | |
1590 | entry->gid_op = &gid_gt; | |
1591 | fallthrough; | |
1592 | case Opt_gid_lt: | |
1593 | case Opt_egid_lt: | |
1594 | if ((token == Opt_gid_lt) || (token == Opt_egid_lt)) | |
1595 | entry->gid_op = &gid_lt; | |
1596 | fallthrough; | |
1597 | case Opt_gid_eq: | |
1598 | case Opt_egid_eq: | |
1599 | eid_token = (token == Opt_egid_eq) || | |
1600 | (token == Opt_egid_gt) || | |
1601 | (token == Opt_egid_lt); | |
1602 | ||
1603 | ima_log_string_op(ab, eid_token ? "egid" : "gid", | |
1604 | args[0].from, token); | |
1605 | ||
1606 | if (gid_valid(entry->gid)) { | |
1607 | result = -EINVAL; | |
1608 | break; | |
1609 | } | |
1610 | ||
1611 | result = kstrtoul(args[0].from, 10, &lnum); | |
1612 | if (!result) { | |
1613 | entry->gid = make_kgid(current_user_ns(), | |
1614 | (gid_t)lnum); | |
1615 | if (!gid_valid(entry->gid) || | |
1616 | (((gid_t)lnum) != lnum)) | |
1617 | result = -EINVAL; | |
1618 | else | |
1619 | entry->flags |= eid_token | |
1620 | ? IMA_EGID : IMA_GID; | |
4af4662f MZ |
1621 | } |
1622 | break; | |
3dd0c8d0 MK |
1623 | case Opt_fowner_gt: |
1624 | entry->fowner_op = &uid_gt; | |
df561f66 | 1625 | fallthrough; |
3dd0c8d0 MK |
1626 | case Opt_fowner_lt: |
1627 | if (token == Opt_fowner_lt) | |
1628 | entry->fowner_op = &uid_lt; | |
df561f66 | 1629 | fallthrough; |
3dd0c8d0 | 1630 | case Opt_fowner_eq: |
40224c41 | 1631 | ima_log_string_op(ab, "fowner", args[0].from, token); |
07f6a794 | 1632 | |
88265322 | 1633 | if (uid_valid(entry->fowner)) { |
07f6a794 MZ |
1634 | result = -EINVAL; |
1635 | break; | |
1636 | } | |
1637 | ||
29707b20 | 1638 | result = kstrtoul(args[0].from, 10, &lnum); |
07f6a794 | 1639 | if (!result) { |
30d8764a AH |
1640 | entry->fowner = make_kuid(current_user_ns(), |
1641 | (uid_t)lnum); | |
1642 | if (!uid_valid(entry->fowner) || | |
1643 | (((uid_t)lnum) != lnum)) | |
07f6a794 MZ |
1644 | result = -EINVAL; |
1645 | else | |
1646 | entry->flags |= IMA_FOWNER; | |
1647 | } | |
1648 | break; | |
40224c41 CV |
1649 | case Opt_fgroup_gt: |
1650 | entry->fgroup_op = &gid_gt; | |
1651 | fallthrough; | |
1652 | case Opt_fgroup_lt: | |
1653 | if (token == Opt_fgroup_lt) | |
1654 | entry->fgroup_op = &gid_lt; | |
1655 | fallthrough; | |
1656 | case Opt_fgroup_eq: | |
1657 | ima_log_string_op(ab, "fgroup", args[0].from, token); | |
1658 | ||
1659 | if (gid_valid(entry->fgroup)) { | |
1660 | result = -EINVAL; | |
1661 | break; | |
1662 | } | |
1663 | ||
1664 | result = kstrtoul(args[0].from, 10, &lnum); | |
1665 | if (!result) { | |
1666 | entry->fgroup = make_kgid(current_user_ns(), | |
1667 | (gid_t)lnum); | |
1668 | if (!gid_valid(entry->fgroup) || | |
1669 | (((gid_t)lnum) != lnum)) | |
1670 | result = -EINVAL; | |
1671 | else | |
1672 | entry->flags |= IMA_FGROUP; | |
1673 | } | |
1674 | break; | |
4af4662f | 1675 | case Opt_obj_user: |
2f1506cd | 1676 | ima_log_string(ab, "obj_user", args[0].from); |
7163a993 | 1677 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
1678 | LSM_OBJ_USER, |
1679 | AUDIT_OBJ_USER); | |
1680 | break; | |
1681 | case Opt_obj_role: | |
2f1506cd | 1682 | ima_log_string(ab, "obj_role", args[0].from); |
7163a993 | 1683 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
1684 | LSM_OBJ_ROLE, |
1685 | AUDIT_OBJ_ROLE); | |
1686 | break; | |
1687 | case Opt_obj_type: | |
2f1506cd | 1688 | ima_log_string(ab, "obj_type", args[0].from); |
7163a993 | 1689 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
1690 | LSM_OBJ_TYPE, |
1691 | AUDIT_OBJ_TYPE); | |
1692 | break; | |
1693 | case Opt_subj_user: | |
2f1506cd | 1694 | ima_log_string(ab, "subj_user", args[0].from); |
7163a993 | 1695 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
1696 | LSM_SUBJ_USER, |
1697 | AUDIT_SUBJ_USER); | |
1698 | break; | |
1699 | case Opt_subj_role: | |
2f1506cd | 1700 | ima_log_string(ab, "subj_role", args[0].from); |
7163a993 | 1701 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
1702 | LSM_SUBJ_ROLE, |
1703 | AUDIT_SUBJ_ROLE); | |
1704 | break; | |
1705 | case Opt_subj_type: | |
2f1506cd | 1706 | ima_log_string(ab, "subj_type", args[0].from); |
7163a993 | 1707 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
1708 | LSM_SUBJ_TYPE, |
1709 | AUDIT_SUBJ_TYPE); | |
1710 | break; | |
0e5a247c | 1711 | case Opt_appraise_type: |
0e5a247c DK |
1712 | ima_log_string(ab, "appraise_type", args[0].from); |
1713 | if ((strcmp(args[0].from, "imasig")) == 0) | |
1714 | entry->flags |= IMA_DIGSIG_REQUIRED; | |
30031b0e | 1715 | else if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) && |
9044d627 TJB |
1716 | strcmp(args[0].from, "imasig|modsig") == 0) |
1717 | entry->flags |= IMA_DIGSIG_REQUIRED | | |
1718 | IMA_MODSIG_ALLOWED; | |
0e5a247c DK |
1719 | else |
1720 | result = -EINVAL; | |
1721 | break; | |
273df864 NJ |
1722 | case Opt_appraise_flag: |
1723 | ima_log_string(ab, "appraise_flag", args[0].from); | |
5f3e9265 TH |
1724 | if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) && |
1725 | strstr(args[0].from, "blacklist")) | |
273df864 | 1726 | entry->flags |= IMA_CHECK_BLACKLIST; |
5f3e9265 TH |
1727 | else |
1728 | result = -EINVAL; | |
273df864 | 1729 | break; |
583a80ae TS |
1730 | case Opt_appraise_algos: |
1731 | ima_log_string(ab, "appraise_algos", args[0].from); | |
1732 | ||
1733 | if (entry->allowed_algos) { | |
1734 | result = -EINVAL; | |
1735 | break; | |
1736 | } | |
1737 | ||
1738 | entry->allowed_algos = | |
1739 | ima_parse_appraise_algos(args[0].from); | |
1740 | /* invalid or empty list of algorithms */ | |
1741 | if (!entry->allowed_algos) { | |
1742 | result = -EINVAL; | |
1743 | break; | |
1744 | } | |
1745 | ||
1746 | entry->flags |= IMA_VALIDATE_ALGOS; | |
1747 | ||
1748 | break; | |
f9b2a735 MZ |
1749 | case Opt_permit_directio: |
1750 | entry->flags |= IMA_PERMIT_DIRECTIO; | |
0260643c ER |
1751 | break; |
1752 | case Opt_pcr: | |
0260643c ER |
1753 | ima_log_string(ab, "pcr", args[0].from); |
1754 | ||
1755 | result = kstrtoint(args[0].from, 10, &entry->pcr); | |
1756 | if (result || INVALID_PCR(entry->pcr)) | |
1757 | result = -EINVAL; | |
1758 | else | |
1759 | entry->flags |= IMA_PCR; | |
1760 | ||
19453ce0 MG |
1761 | break; |
1762 | case Opt_template: | |
1763 | ima_log_string(ab, "template", args[0].from); | |
1764 | if (entry->action != MEASURE) { | |
1765 | result = -EINVAL; | |
1766 | break; | |
1767 | } | |
1768 | template_desc = lookup_template_desc(args[0].from); | |
1769 | if (!template_desc || entry->template) { | |
1770 | result = -EINVAL; | |
1771 | break; | |
1772 | } | |
1773 | ||
1774 | /* | |
1775 | * template_desc_init_fields() does nothing if | |
1776 | * the template is already initialised, so | |
1777 | * it's safe to do this unconditionally | |
1778 | */ | |
1779 | template_desc_init_fields(template_desc->fmt, | |
1780 | &(template_desc->fields), | |
1781 | &(template_desc->num_fields)); | |
1782 | entry->template = template_desc; | |
f9b2a735 | 1783 | break; |
4af4662f | 1784 | case Opt_err: |
2f1506cd | 1785 | ima_log_string(ab, "UNKNOWN", p); |
e9d393bf | 1786 | result = -EINVAL; |
4af4662f MZ |
1787 | break; |
1788 | } | |
1789 | } | |
71218343 | 1790 | if (!result && !ima_validate_rule(entry)) |
4af4662f | 1791 | result = -EINVAL; |
6f0911a6 MZ |
1792 | else if (entry->action == APPRAISE) |
1793 | temp_ima_appraise |= ima_appraise_flag(entry->func); | |
1794 | ||
3878d505 TJB |
1795 | if (!result && entry->flags & IMA_MODSIG_ALLOWED) { |
1796 | template_desc = entry->template ? entry->template : | |
1797 | ima_template_desc_current(); | |
1798 | check_template_modsig(template_desc); | |
1799 | } | |
1800 | ||
b0d5de4d | 1801 | audit_log_format(ab, "res=%d", !result); |
4af4662f MZ |
1802 | audit_log_end(ab); |
1803 | return result; | |
1804 | } | |
1805 | ||
1806 | /** | |
07f6a794 | 1807 | * ima_parse_add_rule - add a rule to ima_policy_rules |
4af4662f MZ |
1808 | * @rule - ima measurement policy rule |
1809 | * | |
38d859f9 | 1810 | * Avoid locking by allowing just one writer at a time in ima_write_policy() |
6ccd0456 | 1811 | * Returns the length of the rule parsed, an error code on failure |
4af4662f | 1812 | */ |
6ccd0456 | 1813 | ssize_t ima_parse_add_rule(char *rule) |
4af4662f | 1814 | { |
52a13284 | 1815 | static const char op[] = "update_policy"; |
6ccd0456 | 1816 | char *p; |
07f6a794 | 1817 | struct ima_rule_entry *entry; |
6ccd0456 | 1818 | ssize_t result, len; |
4af4662f MZ |
1819 | int audit_info = 0; |
1820 | ||
272a6e90 DK |
1821 | p = strsep(&rule, "\n"); |
1822 | len = strlen(p) + 1; | |
7178784f | 1823 | p += strspn(p, " \t"); |
272a6e90 | 1824 | |
7178784f | 1825 | if (*p == '#' || *p == '\0') |
272a6e90 DK |
1826 | return len; |
1827 | ||
4af4662f MZ |
1828 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
1829 | if (!entry) { | |
1830 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | |
1831 | NULL, op, "-ENOMEM", -ENOMEM, audit_info); | |
1832 | return -ENOMEM; | |
1833 | } | |
1834 | ||
1835 | INIT_LIST_HEAD(&entry->list); | |
1836 | ||
6ccd0456 | 1837 | result = ima_parse_rule(p, entry); |
7233e3ee | 1838 | if (result) { |
2bdd737c | 1839 | ima_free_rule(entry); |
523979ad | 1840 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
7e9001f6 | 1841 | NULL, op, "invalid-policy", result, |
523979ad | 1842 | audit_info); |
7233e3ee | 1843 | return result; |
523979ad | 1844 | } |
7233e3ee | 1845 | |
38d859f9 | 1846 | list_add_tail(&entry->list, &ima_temp_rules); |
7233e3ee EP |
1847 | |
1848 | return len; | |
4af4662f MZ |
1849 | } |
1850 | ||
38d859f9 PM |
1851 | /** |
1852 | * ima_delete_rules() called to cleanup invalid in-flight policy. | |
1853 | * We don't need locking as we operate on the temp list, which is | |
1854 | * different from the active one. There is also only one user of | |
1855 | * ima_delete_rules() at a time. | |
1856 | */ | |
64c61d80 | 1857 | void ima_delete_rules(void) |
4af4662f | 1858 | { |
07f6a794 | 1859 | struct ima_rule_entry *entry, *tmp; |
4af4662f | 1860 | |
6ad6afa1 | 1861 | temp_ima_appraise = 0; |
38d859f9 | 1862 | list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) { |
4af4662f | 1863 | list_del(&entry->list); |
465aee77 | 1864 | ima_free_rule(entry); |
4af4662f | 1865 | } |
4af4662f | 1866 | } |
80eae209 | 1867 | |
34e980bb | 1868 | #define __ima_hook_stringify(func, str) (#func), |
39b07096 TJB |
1869 | |
1870 | const char *const func_tokens[] = { | |
1871 | __ima_hooks(__ima_hook_stringify) | |
1872 | }; | |
1873 | ||
80eae209 PM |
1874 | #ifdef CONFIG_IMA_READ_POLICY |
1875 | enum { | |
1876 | mask_exec = 0, mask_write, mask_read, mask_append | |
1877 | }; | |
1878 | ||
bb543e39 | 1879 | static const char *const mask_tokens[] = { |
8cdc23a3 RS |
1880 | "^MAY_EXEC", |
1881 | "^MAY_WRITE", | |
1882 | "^MAY_READ", | |
1883 | "^MAY_APPEND" | |
80eae209 PM |
1884 | }; |
1885 | ||
80eae209 PM |
1886 | void *ima_policy_start(struct seq_file *m, loff_t *pos) |
1887 | { | |
1888 | loff_t l = *pos; | |
1889 | struct ima_rule_entry *entry; | |
eb0782bb | 1890 | struct list_head *ima_rules_tmp; |
80eae209 PM |
1891 | |
1892 | rcu_read_lock(); | |
eb0782bb | 1893 | ima_rules_tmp = rcu_dereference(ima_rules); |
1894 | list_for_each_entry_rcu(entry, ima_rules_tmp, list) { | |
80eae209 PM |
1895 | if (!l--) { |
1896 | rcu_read_unlock(); | |
1897 | return entry; | |
1898 | } | |
1899 | } | |
1900 | rcu_read_unlock(); | |
1901 | return NULL; | |
1902 | } | |
1903 | ||
1904 | void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) | |
1905 | { | |
1906 | struct ima_rule_entry *entry = v; | |
1907 | ||
1908 | rcu_read_lock(); | |
1909 | entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list); | |
1910 | rcu_read_unlock(); | |
1911 | (*pos)++; | |
1912 | ||
eb0782bb | 1913 | return (&entry->list == &ima_default_rules || |
1914 | &entry->list == &ima_policy_rules) ? NULL : entry; | |
80eae209 PM |
1915 | } |
1916 | ||
1917 | void ima_policy_stop(struct seq_file *m, void *v) | |
1918 | { | |
1919 | } | |
1920 | ||
1a9430db | 1921 | #define pt(token) policy_tokens[token].pattern |
80eae209 | 1922 | #define mt(token) mask_tokens[token] |
80eae209 | 1923 | |
b5269ab3 MZ |
1924 | /* |
1925 | * policy_func_show - display the ima_hooks policy rule | |
1926 | */ | |
1927 | static void policy_func_show(struct seq_file *m, enum ima_hooks func) | |
1928 | { | |
2663218b TJB |
1929 | if (func > 0 && func < MAX_CHECK) |
1930 | seq_printf(m, "func=%s ", func_tokens[func]); | |
1931 | else | |
1932 | seq_printf(m, "func=%d ", func); | |
b5269ab3 MZ |
1933 | } |
1934 | ||
176377d9 TH |
1935 | static void ima_show_rule_opt_list(struct seq_file *m, |
1936 | const struct ima_rule_opt_list *opt_list) | |
1937 | { | |
1938 | size_t i; | |
1939 | ||
1940 | for (i = 0; i < opt_list->count; i++) | |
1941 | seq_printf(m, "%s%s", i ? "|" : "", opt_list->items[i]); | |
1942 | } | |
1943 | ||
583a80ae TS |
1944 | static void ima_policy_show_appraise_algos(struct seq_file *m, |
1945 | unsigned int allowed_hashes) | |
1946 | { | |
1947 | int idx, list_size = 0; | |
1948 | ||
1949 | for (idx = 0; idx < HASH_ALGO__LAST; idx++) { | |
1950 | if (!(allowed_hashes & (1U << idx))) | |
1951 | continue; | |
1952 | ||
1953 | /* only add commas if the list contains multiple entries */ | |
1954 | if (list_size++) | |
1955 | seq_puts(m, ","); | |
1956 | ||
1957 | seq_puts(m, hash_algo_name[idx]); | |
1958 | } | |
1959 | } | |
1960 | ||
80eae209 PM |
1961 | int ima_policy_show(struct seq_file *m, void *v) |
1962 | { | |
1963 | struct ima_rule_entry *entry = v; | |
b8b57278 | 1964 | int i; |
80eae209 | 1965 | char tbuf[64] = {0,}; |
8cdc23a3 | 1966 | int offset = 0; |
80eae209 PM |
1967 | |
1968 | rcu_read_lock(); | |
1969 | ||
89677197 SB |
1970 | /* Do not print rules with inactive LSM labels */ |
1971 | for (i = 0; i < MAX_LSM_RULES; i++) { | |
1972 | if (entry->lsm[i].args_p && !entry->lsm[i].rule) { | |
1973 | rcu_read_unlock(); | |
1974 | return 0; | |
1975 | } | |
1976 | } | |
1977 | ||
80eae209 PM |
1978 | if (entry->action & MEASURE) |
1979 | seq_puts(m, pt(Opt_measure)); | |
1980 | if (entry->action & DONT_MEASURE) | |
1981 | seq_puts(m, pt(Opt_dont_measure)); | |
1982 | if (entry->action & APPRAISE) | |
1983 | seq_puts(m, pt(Opt_appraise)); | |
1984 | if (entry->action & DONT_APPRAISE) | |
1985 | seq_puts(m, pt(Opt_dont_appraise)); | |
1986 | if (entry->action & AUDIT) | |
1987 | seq_puts(m, pt(Opt_audit)); | |
da1b0029 MZ |
1988 | if (entry->action & HASH) |
1989 | seq_puts(m, pt(Opt_hash)); | |
1990 | if (entry->action & DONT_HASH) | |
1991 | seq_puts(m, pt(Opt_dont_hash)); | |
80eae209 PM |
1992 | |
1993 | seq_puts(m, " "); | |
1994 | ||
b5269ab3 MZ |
1995 | if (entry->flags & IMA_FUNC) |
1996 | policy_func_show(m, entry->func); | |
80eae209 | 1997 | |
8cdc23a3 RS |
1998 | if ((entry->flags & IMA_MASK) || (entry->flags & IMA_INMASK)) { |
1999 | if (entry->flags & IMA_MASK) | |
2000 | offset = 1; | |
80eae209 | 2001 | if (entry->mask & MAY_EXEC) |
8cdc23a3 | 2002 | seq_printf(m, pt(Opt_mask), mt(mask_exec) + offset); |
80eae209 | 2003 | if (entry->mask & MAY_WRITE) |
8cdc23a3 | 2004 | seq_printf(m, pt(Opt_mask), mt(mask_write) + offset); |
80eae209 | 2005 | if (entry->mask & MAY_READ) |
8cdc23a3 | 2006 | seq_printf(m, pt(Opt_mask), mt(mask_read) + offset); |
80eae209 | 2007 | if (entry->mask & MAY_APPEND) |
8cdc23a3 | 2008 | seq_printf(m, pt(Opt_mask), mt(mask_append) + offset); |
80eae209 PM |
2009 | seq_puts(m, " "); |
2010 | } | |
2011 | ||
2012 | if (entry->flags & IMA_FSMAGIC) { | |
2013 | snprintf(tbuf, sizeof(tbuf), "0x%lx", entry->fsmagic); | |
2014 | seq_printf(m, pt(Opt_fsmagic), tbuf); | |
2015 | seq_puts(m, " "); | |
2016 | } | |
2017 | ||
f1b08bbc MZ |
2018 | if (entry->flags & IMA_FSNAME) { |
2019 | snprintf(tbuf, sizeof(tbuf), "%s", entry->fsname); | |
2020 | seq_printf(m, pt(Opt_fsname), tbuf); | |
2021 | seq_puts(m, " "); | |
2022 | } | |
2023 | ||
2b60c0ec | 2024 | if (entry->flags & IMA_KEYRINGS) { |
176377d9 TH |
2025 | seq_puts(m, "keyrings="); |
2026 | ima_show_rule_opt_list(m, entry->keyrings); | |
2b60c0ec LR |
2027 | seq_puts(m, " "); |
2028 | } | |
2029 | ||
47d76a48 TS |
2030 | if (entry->flags & IMA_LABEL) { |
2031 | seq_puts(m, "label="); | |
2032 | ima_show_rule_opt_list(m, entry->label); | |
2033 | seq_puts(m, " "); | |
2034 | } | |
2035 | ||
0260643c ER |
2036 | if (entry->flags & IMA_PCR) { |
2037 | snprintf(tbuf, sizeof(tbuf), "%d", entry->pcr); | |
2038 | seq_printf(m, pt(Opt_pcr), tbuf); | |
2039 | seq_puts(m, " "); | |
2040 | } | |
2041 | ||
80eae209 | 2042 | if (entry->flags & IMA_FSUUID) { |
787d8c53 | 2043 | seq_printf(m, "fsuuid=%pU", &entry->fsuuid); |
80eae209 PM |
2044 | seq_puts(m, " "); |
2045 | } | |
2046 | ||
2047 | if (entry->flags & IMA_UID) { | |
2048 | snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); | |
3dd0c8d0 MK |
2049 | if (entry->uid_op == &uid_gt) |
2050 | seq_printf(m, pt(Opt_uid_gt), tbuf); | |
2051 | else if (entry->uid_op == &uid_lt) | |
2052 | seq_printf(m, pt(Opt_uid_lt), tbuf); | |
2053 | else | |
2054 | seq_printf(m, pt(Opt_uid_eq), tbuf); | |
80eae209 PM |
2055 | seq_puts(m, " "); |
2056 | } | |
2057 | ||
2058 | if (entry->flags & IMA_EUID) { | |
2059 | snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); | |
3dd0c8d0 MK |
2060 | if (entry->uid_op == &uid_gt) |
2061 | seq_printf(m, pt(Opt_euid_gt), tbuf); | |
2062 | else if (entry->uid_op == &uid_lt) | |
2063 | seq_printf(m, pt(Opt_euid_lt), tbuf); | |
2064 | else | |
2065 | seq_printf(m, pt(Opt_euid_eq), tbuf); | |
80eae209 PM |
2066 | seq_puts(m, " "); |
2067 | } | |
2068 | ||
40224c41 CV |
2069 | if (entry->flags & IMA_GID) { |
2070 | snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid)); | |
2071 | if (entry->gid_op == &gid_gt) | |
2072 | seq_printf(m, pt(Opt_gid_gt), tbuf); | |
2073 | else if (entry->gid_op == &gid_lt) | |
2074 | seq_printf(m, pt(Opt_gid_lt), tbuf); | |
2075 | else | |
2076 | seq_printf(m, pt(Opt_gid_eq), tbuf); | |
2077 | seq_puts(m, " "); | |
2078 | } | |
2079 | ||
2080 | if (entry->flags & IMA_EGID) { | |
2081 | snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid)); | |
2082 | if (entry->gid_op == &gid_gt) | |
2083 | seq_printf(m, pt(Opt_egid_gt), tbuf); | |
2084 | else if (entry->gid_op == &gid_lt) | |
2085 | seq_printf(m, pt(Opt_egid_lt), tbuf); | |
2086 | else | |
2087 | seq_printf(m, pt(Opt_egid_eq), tbuf); | |
2088 | seq_puts(m, " "); | |
2089 | } | |
2090 | ||
80eae209 PM |
2091 | if (entry->flags & IMA_FOWNER) { |
2092 | snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); | |
3dd0c8d0 MK |
2093 | if (entry->fowner_op == &uid_gt) |
2094 | seq_printf(m, pt(Opt_fowner_gt), tbuf); | |
2095 | else if (entry->fowner_op == &uid_lt) | |
2096 | seq_printf(m, pt(Opt_fowner_lt), tbuf); | |
2097 | else | |
2098 | seq_printf(m, pt(Opt_fowner_eq), tbuf); | |
80eae209 PM |
2099 | seq_puts(m, " "); |
2100 | } | |
2101 | ||
40224c41 CV |
2102 | if (entry->flags & IMA_FGROUP) { |
2103 | snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup)); | |
2104 | if (entry->fgroup_op == &gid_gt) | |
2105 | seq_printf(m, pt(Opt_fgroup_gt), tbuf); | |
2106 | else if (entry->fgroup_op == &gid_lt) | |
2107 | seq_printf(m, pt(Opt_fgroup_lt), tbuf); | |
2108 | else | |
2109 | seq_printf(m, pt(Opt_fgroup_eq), tbuf); | |
2110 | seq_puts(m, " "); | |
2111 | } | |
2112 | ||
583a80ae TS |
2113 | if (entry->flags & IMA_VALIDATE_ALGOS) { |
2114 | seq_puts(m, "appraise_algos="); | |
2115 | ima_policy_show_appraise_algos(m, entry->allowed_algos); | |
2116 | seq_puts(m, " "); | |
2117 | } | |
2118 | ||
80eae209 PM |
2119 | for (i = 0; i < MAX_LSM_RULES; i++) { |
2120 | if (entry->lsm[i].rule) { | |
2121 | switch (i) { | |
2122 | case LSM_OBJ_USER: | |
2123 | seq_printf(m, pt(Opt_obj_user), | |
aa0c0227 | 2124 | entry->lsm[i].args_p); |
80eae209 PM |
2125 | break; |
2126 | case LSM_OBJ_ROLE: | |
2127 | seq_printf(m, pt(Opt_obj_role), | |
aa0c0227 | 2128 | entry->lsm[i].args_p); |
80eae209 PM |
2129 | break; |
2130 | case LSM_OBJ_TYPE: | |
2131 | seq_printf(m, pt(Opt_obj_type), | |
aa0c0227 | 2132 | entry->lsm[i].args_p); |
80eae209 PM |
2133 | break; |
2134 | case LSM_SUBJ_USER: | |
2135 | seq_printf(m, pt(Opt_subj_user), | |
aa0c0227 | 2136 | entry->lsm[i].args_p); |
80eae209 PM |
2137 | break; |
2138 | case LSM_SUBJ_ROLE: | |
2139 | seq_printf(m, pt(Opt_subj_role), | |
aa0c0227 | 2140 | entry->lsm[i].args_p); |
80eae209 PM |
2141 | break; |
2142 | case LSM_SUBJ_TYPE: | |
2143 | seq_printf(m, pt(Opt_subj_type), | |
aa0c0227 | 2144 | entry->lsm[i].args_p); |
80eae209 PM |
2145 | break; |
2146 | } | |
5350ceb0 | 2147 | seq_puts(m, " "); |
80eae209 PM |
2148 | } |
2149 | } | |
19453ce0 MG |
2150 | if (entry->template) |
2151 | seq_printf(m, "template=%s ", entry->template->name); | |
9044d627 TJB |
2152 | if (entry->flags & IMA_DIGSIG_REQUIRED) { |
2153 | if (entry->flags & IMA_MODSIG_ALLOWED) | |
2154 | seq_puts(m, "appraise_type=imasig|modsig "); | |
2155 | else | |
2156 | seq_puts(m, "appraise_type=imasig "); | |
2157 | } | |
273df864 NJ |
2158 | if (entry->flags & IMA_CHECK_BLACKLIST) |
2159 | seq_puts(m, "appraise_flag=check_blacklist "); | |
80eae209 PM |
2160 | if (entry->flags & IMA_PERMIT_DIRECTIO) |
2161 | seq_puts(m, "permit_directio "); | |
2162 | rcu_read_unlock(); | |
2163 | seq_puts(m, "\n"); | |
2164 | return 0; | |
2165 | } | |
2166 | #endif /* CONFIG_IMA_READ_POLICY */ | |
29d3c1c8 MG |
2167 | |
2168 | #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) | |
2169 | /* | |
2170 | * ima_appraise_signature: whether IMA will appraise a given function using | |
2171 | * an IMA digital signature. This is restricted to cases where the kernel | |
2172 | * has a set of built-in trusted keys in order to avoid an attacker simply | |
2173 | * loading additional keys. | |
2174 | */ | |
2175 | bool ima_appraise_signature(enum kernel_read_file_id id) | |
2176 | { | |
2177 | struct ima_rule_entry *entry; | |
2178 | bool found = false; | |
2179 | enum ima_hooks func; | |
eb0782bb | 2180 | struct list_head *ima_rules_tmp; |
29d3c1c8 MG |
2181 | |
2182 | if (id >= READING_MAX_ID) | |
2183 | return false; | |
2184 | ||
2185 | func = read_idmap[id] ?: FILE_CHECK; | |
2186 | ||
2187 | rcu_read_lock(); | |
eb0782bb | 2188 | ima_rules_tmp = rcu_dereference(ima_rules); |
2189 | list_for_each_entry_rcu(entry, ima_rules_tmp, list) { | |
29d3c1c8 MG |
2190 | if (entry->action != APPRAISE) |
2191 | continue; | |
2192 | ||
2193 | /* | |
2194 | * A generic entry will match, but otherwise require that it | |
2195 | * match the func we're looking for | |
2196 | */ | |
2197 | if (entry->func && entry->func != func) | |
2198 | continue; | |
2199 | ||
2200 | /* | |
2201 | * We require this to be a digital signature, not a raw IMA | |
2202 | * hash. | |
2203 | */ | |
2204 | if (entry->flags & IMA_DIGSIG_REQUIRED) | |
2205 | found = true; | |
2206 | ||
2207 | /* | |
2208 | * We've found a rule that matches, so break now even if it | |
2209 | * didn't require a digital signature - a later rule that does | |
2210 | * won't override it, so would be a false positive. | |
2211 | */ | |
2212 | break; | |
2213 | } | |
2214 | ||
2215 | rcu_read_unlock(); | |
2216 | return found; | |
2217 | } | |
2218 | #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */ |