Commit | Line | Data |
---|---|---|
3323eec9 MZ |
1 | /* |
2 | * Copyright (C) 2008 IBM Corporation | |
3 | * Author: Mimi Zohar <zohar@us.ibm.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, version 2 of the License. | |
8 | * | |
9 | * ima_policy.c | |
2bb930ab | 10 | * - initialize default measure policy rules |
3323eec9 MZ |
11 | * |
12 | */ | |
13 | #include <linux/module.h> | |
14 | #include <linux/list.h> | |
cf222217 | 15 | #include <linux/fs.h> |
3323eec9 MZ |
16 | #include <linux/security.h> |
17 | #include <linux/magic.h> | |
4af4662f | 18 | #include <linux/parser.h> |
5a0e3ad6 | 19 | #include <linux/slab.h> |
38d859f9 | 20 | #include <linux/rculist.h> |
85865c1f | 21 | #include <linux/genhd.h> |
80eae209 | 22 | #include <linux/seq_file.h> |
3323eec9 MZ |
23 | |
24 | #include "ima.h" | |
25 | ||
26 | /* flags definitions */ | |
2bb930ab DK |
27 | #define IMA_FUNC 0x0001 |
28 | #define IMA_MASK 0x0002 | |
3323eec9 MZ |
29 | #define IMA_FSMAGIC 0x0004 |
30 | #define IMA_UID 0x0008 | |
07f6a794 | 31 | #define IMA_FOWNER 0x0010 |
85865c1f | 32 | #define IMA_FSUUID 0x0020 |
4351c294 | 33 | #define IMA_INMASK 0x0040 |
139069ef | 34 | #define IMA_EUID 0x0080 |
3323eec9 | 35 | |
45e2472e DK |
36 | #define UNKNOWN 0 |
37 | #define MEASURE 0x0001 /* same as IMA_MEASURE */ | |
38 | #define DONT_MEASURE 0x0002 | |
39 | #define APPRAISE 0x0004 /* same as IMA_APPRAISE */ | |
40 | #define DONT_APPRAISE 0x0008 | |
e7c568e0 | 41 | #define AUDIT 0x0040 |
4af4662f | 42 | |
a756024e | 43 | int ima_policy_flag; |
6ad6afa1 | 44 | static int temp_ima_appraise; |
a756024e | 45 | |
4af4662f MZ |
46 | #define MAX_LSM_RULES 6 |
47 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | |
48 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE | |
49 | }; | |
3323eec9 | 50 | |
24fd03c8 MZ |
51 | enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; |
52 | ||
07f6a794 | 53 | struct ima_rule_entry { |
3323eec9 | 54 | struct list_head list; |
2fe5d6de | 55 | int action; |
3323eec9 MZ |
56 | unsigned int flags; |
57 | enum ima_hooks func; | |
58 | int mask; | |
59 | unsigned long fsmagic; | |
85865c1f | 60 | u8 fsuuid[16]; |
8b94eea4 | 61 | kuid_t uid; |
88265322 | 62 | kuid_t fowner; |
4af4662f MZ |
63 | struct { |
64 | void *rule; /* LSM file metadata specific */ | |
7163a993 | 65 | void *args_p; /* audit value */ |
4af4662f MZ |
66 | int type; /* audit type */ |
67 | } lsm[MAX_LSM_RULES]; | |
3323eec9 MZ |
68 | }; |
69 | ||
5789ba3b EP |
70 | /* |
71 | * Without LSM specific knowledge, the default policy can only be | |
07f6a794 | 72 | * written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner |
4af4662f | 73 | */ |
5789ba3b EP |
74 | |
75 | /* | |
76 | * The minimum rule set to allow for full TCB coverage. Measures all files | |
77 | * opened or mmap for exec and everything read by root. Dangerous because | |
78 | * normal users can easily run the machine out of memory simply building | |
79 | * and running executables. | |
80 | */ | |
24fd03c8 | 81 | static struct ima_rule_entry dont_measure_rules[] = { |
2bb930ab DK |
82 | {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
83 | {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, | |
84 | {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, | |
85 | {.action = DONT_MEASURE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, | |
86 | {.action = DONT_MEASURE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, | |
87 | {.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, | |
88 | {.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, | |
89 | {.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, | |
6438de9f RS |
90 | {.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC, |
91 | .flags = IMA_FSMAGIC}, | |
24fd03c8 MZ |
92 | {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC} |
93 | }; | |
94 | ||
95 | static struct ima_rule_entry original_measurement_rules[] = { | |
96 | {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, | |
97 | .flags = IMA_FUNC | IMA_MASK}, | |
98 | {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, | |
99 | .flags = IMA_FUNC | IMA_MASK}, | |
100 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, | |
101 | .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | |
102 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, | |
103 | {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, | |
104 | }; | |
105 | ||
106 | static struct ima_rule_entry default_measurement_rules[] = { | |
2bb930ab | 107 | {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, |
3323eec9 | 108 | .flags = IMA_FUNC | IMA_MASK}, |
2bb930ab | 109 | {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, |
3323eec9 | 110 | .flags = IMA_FUNC | IMA_MASK}, |
24fd03c8 MZ |
111 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, |
112 | .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, | |
113 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, | |
114 | .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, | |
2bb930ab | 115 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, |
5a9196d7 | 116 | {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, |
19f8a847 | 117 | {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, |
3323eec9 MZ |
118 | }; |
119 | ||
07f6a794 | 120 | static struct ima_rule_entry default_appraise_rules[] = { |
2bb930ab DK |
121 | {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
122 | {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, | |
123 | {.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, | |
124 | {.action = DONT_APPRAISE, .fsmagic = TMPFS_MAGIC, .flags = IMA_FSMAGIC}, | |
125 | {.action = DONT_APPRAISE, .fsmagic = RAMFS_MAGIC, .flags = IMA_FSMAGIC}, | |
126 | {.action = DONT_APPRAISE, .fsmagic = DEVPTS_SUPER_MAGIC, .flags = IMA_FSMAGIC}, | |
127 | {.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC}, | |
128 | {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC}, | |
129 | {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC}, | |
cd025f7f | 130 | {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}, |
2bb930ab | 131 | {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC}, |
95ee08fa MZ |
132 | #ifdef CONFIG_IMA_WRITE_POLICY |
133 | {.action = APPRAISE, .func = POLICY_CHECK, | |
134 | .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, | |
135 | #endif | |
c57782c1 | 136 | #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT |
2bb930ab | 137 | {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, |
c57782c1 DK |
138 | #else |
139 | /* force signature */ | |
140 | {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, | |
141 | .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, | |
142 | #endif | |
07f6a794 MZ |
143 | }; |
144 | ||
145 | static LIST_HEAD(ima_default_rules); | |
146 | static LIST_HEAD(ima_policy_rules); | |
38d859f9 | 147 | static LIST_HEAD(ima_temp_rules); |
07f6a794 | 148 | static struct list_head *ima_rules; |
3323eec9 | 149 | |
24fd03c8 | 150 | static int ima_policy __initdata; |
38d859f9 | 151 | |
07f6a794 | 152 | static int __init default_measure_policy_setup(char *str) |
5789ba3b | 153 | { |
24fd03c8 MZ |
154 | if (ima_policy) |
155 | return 1; | |
156 | ||
157 | ima_policy = ORIGINAL_TCB; | |
5789ba3b EP |
158 | return 1; |
159 | } | |
07f6a794 MZ |
160 | __setup("ima_tcb", default_measure_policy_setup); |
161 | ||
24fd03c8 MZ |
162 | static int __init policy_setup(char *str) |
163 | { | |
164 | if (ima_policy) | |
165 | return 1; | |
166 | ||
167 | if (strcmp(str, "tcb") == 0) | |
168 | ima_policy = DEFAULT_TCB; | |
169 | ||
170 | return 1; | |
171 | } | |
172 | __setup("ima_policy=", policy_setup); | |
173 | ||
07f6a794 MZ |
174 | static bool ima_use_appraise_tcb __initdata; |
175 | static int __init default_appraise_policy_setup(char *str) | |
176 | { | |
177 | ima_use_appraise_tcb = 1; | |
178 | return 1; | |
179 | } | |
180 | __setup("ima_appraise_tcb", default_appraise_policy_setup); | |
5789ba3b | 181 | |
2bb930ab | 182 | /* |
38d859f9 PM |
183 | * The LSM policy can be reloaded, leaving the IMA LSM based rules referring |
184 | * to the old, stale LSM policy. Update the IMA LSM based rules to reflect | |
185 | * the reloaded LSM policy. We assume the rules still exist; and BUG_ON() if | |
186 | * they don't. | |
7163a993 MZ |
187 | */ |
188 | static void ima_lsm_update_rules(void) | |
189 | { | |
38d859f9 | 190 | struct ima_rule_entry *entry; |
7163a993 MZ |
191 | int result; |
192 | int i; | |
193 | ||
38d859f9 | 194 | list_for_each_entry(entry, &ima_policy_rules, list) { |
7163a993 MZ |
195 | for (i = 0; i < MAX_LSM_RULES; i++) { |
196 | if (!entry->lsm[i].rule) | |
197 | continue; | |
198 | result = security_filter_rule_init(entry->lsm[i].type, | |
199 | Audit_equal, | |
200 | entry->lsm[i].args_p, | |
201 | &entry->lsm[i].rule); | |
202 | BUG_ON(!entry->lsm[i].rule); | |
203 | } | |
204 | } | |
7163a993 MZ |
205 | } |
206 | ||
3323eec9 MZ |
207 | /** |
208 | * ima_match_rules - determine whether an inode matches the measure rule. | |
209 | * @rule: a pointer to a rule | |
210 | * @inode: a pointer to an inode | |
211 | * @func: LIM hook identifier | |
212 | * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) | |
213 | * | |
214 | * Returns true on rule match, false on failure. | |
215 | */ | |
4ad87a3d MZ |
216 | static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, |
217 | enum ima_hooks func, int mask) | |
3323eec9 MZ |
218 | { |
219 | struct task_struct *tsk = current; | |
3db59dd9 | 220 | const struct cred *cred = current_cred(); |
4af4662f | 221 | int i; |
3323eec9 | 222 | |
09b1148e DK |
223 | if ((rule->flags & IMA_FUNC) && |
224 | (rule->func != func && func != POST_SETATTR)) | |
3323eec9 | 225 | return false; |
09b1148e DK |
226 | if ((rule->flags & IMA_MASK) && |
227 | (rule->mask != mask && func != POST_SETATTR)) | |
3323eec9 | 228 | return false; |
4351c294 MZ |
229 | if ((rule->flags & IMA_INMASK) && |
230 | (!(rule->mask & mask) && func != POST_SETATTR)) | |
231 | return false; | |
3323eec9 MZ |
232 | if ((rule->flags & IMA_FSMAGIC) |
233 | && rule->fsmagic != inode->i_sb->s_magic) | |
234 | return false; | |
85865c1f | 235 | if ((rule->flags & IMA_FSUUID) && |
446d64e3 | 236 | memcmp(rule->fsuuid, inode->i_sb->s_uuid, sizeof(rule->fsuuid))) |
85865c1f | 237 | return false; |
8b94eea4 | 238 | if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) |
3323eec9 | 239 | return false; |
139069ef MZ |
240 | if (rule->flags & IMA_EUID) { |
241 | if (has_capability_noaudit(current, CAP_SETUID)) { | |
242 | if (!uid_eq(rule->uid, cred->euid) | |
243 | && !uid_eq(rule->uid, cred->suid) | |
244 | && !uid_eq(rule->uid, cred->uid)) | |
245 | return false; | |
246 | } else if (!uid_eq(rule->uid, cred->euid)) | |
247 | return false; | |
248 | } | |
249 | ||
88265322 | 250 | if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid)) |
07f6a794 | 251 | return false; |
4af4662f | 252 | for (i = 0; i < MAX_LSM_RULES; i++) { |
53fc0e22 | 253 | int rc = 0; |
4af4662f | 254 | u32 osid, sid; |
7163a993 | 255 | int retried = 0; |
4af4662f MZ |
256 | |
257 | if (!rule->lsm[i].rule) | |
258 | continue; | |
7163a993 | 259 | retry: |
4af4662f MZ |
260 | switch (i) { |
261 | case LSM_OBJ_USER: | |
262 | case LSM_OBJ_ROLE: | |
263 | case LSM_OBJ_TYPE: | |
264 | security_inode_getsecid(inode, &osid); | |
265 | rc = security_filter_rule_match(osid, | |
266 | rule->lsm[i].type, | |
53fc0e22 | 267 | Audit_equal, |
4af4662f MZ |
268 | rule->lsm[i].rule, |
269 | NULL); | |
270 | break; | |
271 | case LSM_SUBJ_USER: | |
272 | case LSM_SUBJ_ROLE: | |
273 | case LSM_SUBJ_TYPE: | |
274 | security_task_getsecid(tsk, &sid); | |
275 | rc = security_filter_rule_match(sid, | |
276 | rule->lsm[i].type, | |
53fc0e22 | 277 | Audit_equal, |
4af4662f MZ |
278 | rule->lsm[i].rule, |
279 | NULL); | |
280 | default: | |
281 | break; | |
282 | } | |
7163a993 MZ |
283 | if ((rc < 0) && (!retried)) { |
284 | retried = 1; | |
285 | ima_lsm_update_rules(); | |
286 | goto retry; | |
2bb930ab | 287 | } |
4af4662f MZ |
288 | if (!rc) |
289 | return false; | |
290 | } | |
3323eec9 MZ |
291 | return true; |
292 | } | |
293 | ||
d79d72e0 MZ |
294 | /* |
295 | * In addition to knowing that we need to appraise the file in general, | |
5a73fcfa | 296 | * we need to differentiate between calling hooks, for hook specific rules. |
d79d72e0 | 297 | */ |
4ad87a3d | 298 | static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) |
d79d72e0 | 299 | { |
5a73fcfa MZ |
300 | if (!(rule->flags & IMA_FUNC)) |
301 | return IMA_FILE_APPRAISE; | |
302 | ||
2bb930ab | 303 | switch (func) { |
d79d72e0 MZ |
304 | case MMAP_CHECK: |
305 | return IMA_MMAP_APPRAISE; | |
306 | case BPRM_CHECK: | |
307 | return IMA_BPRM_APPRAISE; | |
d79d72e0 | 308 | case FILE_CHECK: |
c6af8efe | 309 | case POST_SETATTR: |
d79d72e0 | 310 | return IMA_FILE_APPRAISE; |
c6af8efe MZ |
311 | case MODULE_CHECK ... MAX_CHECK - 1: |
312 | default: | |
313 | return IMA_READ_APPRAISE; | |
d79d72e0 MZ |
314 | } |
315 | } | |
316 | ||
3323eec9 MZ |
317 | /** |
318 | * ima_match_policy - decision based on LSM and other conditions | |
319 | * @inode: pointer to an inode for which the policy decision is being made | |
320 | * @func: IMA hook identifier | |
321 | * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) | |
322 | * | |
323 | * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) | |
324 | * conditions. | |
325 | * | |
38d859f9 PM |
326 | * Since the IMA policy may be updated multiple times we need to lock the |
327 | * list when walking it. Reads are many orders of magnitude more numerous | |
328 | * than writes so ima_match_policy() is classical RCU candidate. | |
3323eec9 | 329 | */ |
2fe5d6de MZ |
330 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
331 | int flags) | |
3323eec9 | 332 | { |
07f6a794 | 333 | struct ima_rule_entry *entry; |
2fe5d6de | 334 | int action = 0, actmask = flags | (flags << 1); |
3323eec9 | 335 | |
38d859f9 PM |
336 | rcu_read_lock(); |
337 | list_for_each_entry_rcu(entry, ima_rules, list) { | |
3323eec9 | 338 | |
2fe5d6de MZ |
339 | if (!(entry->action & actmask)) |
340 | continue; | |
341 | ||
342 | if (!ima_match_rules(entry, inode, func, mask)) | |
343 | continue; | |
3323eec9 | 344 | |
0e5a247c DK |
345 | action |= entry->flags & IMA_ACTION_FLAGS; |
346 | ||
45e2472e | 347 | action |= entry->action & IMA_DO_MASK; |
d79d72e0 | 348 | if (entry->action & IMA_APPRAISE) |
5a73fcfa | 349 | action |= get_subaction(entry, func); |
d79d72e0 | 350 | |
45e2472e DK |
351 | if (entry->action & IMA_DO_MASK) |
352 | actmask &= ~(entry->action | entry->action << 1); | |
353 | else | |
354 | actmask &= ~(entry->action | entry->action >> 1); | |
3323eec9 | 355 | |
2fe5d6de MZ |
356 | if (!actmask) |
357 | break; | |
3323eec9 | 358 | } |
38d859f9 | 359 | rcu_read_unlock(); |
2fe5d6de MZ |
360 | |
361 | return action; | |
3323eec9 MZ |
362 | } |
363 | ||
a756024e RS |
364 | /* |
365 | * Initialize the ima_policy_flag variable based on the currently | |
366 | * loaded policy. Based on this flag, the decision to short circuit | |
367 | * out of a function or not call the function in the first place | |
368 | * can be made earlier. | |
369 | */ | |
370 | void ima_update_policy_flag(void) | |
371 | { | |
372 | struct ima_rule_entry *entry; | |
373 | ||
a756024e RS |
374 | list_for_each_entry(entry, ima_rules, list) { |
375 | if (entry->action & IMA_DO_MASK) | |
376 | ima_policy_flag |= entry->action; | |
377 | } | |
378 | ||
6ad6afa1 | 379 | ima_appraise |= temp_ima_appraise; |
a756024e RS |
380 | if (!ima_appraise) |
381 | ima_policy_flag &= ~IMA_APPRAISE; | |
382 | } | |
383 | ||
3323eec9 MZ |
384 | /** |
385 | * ima_init_policy - initialize the default measure rules. | |
386 | * | |
07f6a794 MZ |
387 | * ima_rules points to either the ima_default_rules or the |
388 | * the new ima_policy_rules. | |
3323eec9 | 389 | */ |
932995f0 | 390 | void __init ima_init_policy(void) |
3323eec9 | 391 | { |
07f6a794 | 392 | int i, measure_entries, appraise_entries; |
5789ba3b | 393 | |
24fd03c8 MZ |
394 | /* if !ima_policy set entries = 0 so we load NO default rules */ |
395 | measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0; | |
07f6a794 MZ |
396 | appraise_entries = ima_use_appraise_tcb ? |
397 | ARRAY_SIZE(default_appraise_rules) : 0; | |
2bb930ab | 398 | |
5577857f | 399 | for (i = 0; i < measure_entries; i++) |
24fd03c8 MZ |
400 | list_add_tail(&dont_measure_rules[i].list, &ima_default_rules); |
401 | ||
402 | switch (ima_policy) { | |
403 | case ORIGINAL_TCB: | |
404 | for (i = 0; i < ARRAY_SIZE(original_measurement_rules); i++) | |
405 | list_add_tail(&original_measurement_rules[i].list, | |
406 | &ima_default_rules); | |
407 | break; | |
408 | case DEFAULT_TCB: | |
409 | for (i = 0; i < ARRAY_SIZE(default_measurement_rules); i++) | |
410 | list_add_tail(&default_measurement_rules[i].list, | |
411 | &ima_default_rules); | |
412 | default: | |
413 | break; | |
414 | } | |
5577857f DC |
415 | |
416 | for (i = 0; i < appraise_entries; i++) { | |
417 | list_add_tail(&default_appraise_rules[i].list, | |
418 | &ima_default_rules); | |
95ee08fa MZ |
419 | if (default_appraise_rules[i].func == POLICY_CHECK) |
420 | temp_ima_appraise |= IMA_APPRAISE_POLICY; | |
07f6a794 MZ |
421 | } |
422 | ||
423 | ima_rules = &ima_default_rules; | |
95ee08fa | 424 | ima_update_policy_flag(); |
3323eec9 | 425 | } |
4af4662f | 426 | |
0112721d | 427 | /* Make sure we have a valid policy, at least containing some rules. */ |
c75d8e96 | 428 | int ima_check_policy(void) |
0112721d SL |
429 | { |
430 | if (list_empty(&ima_temp_rules)) | |
431 | return -EINVAL; | |
432 | return 0; | |
433 | } | |
434 | ||
4af4662f MZ |
435 | /** |
436 | * ima_update_policy - update default_rules with new measure rules | |
437 | * | |
438 | * Called on file .release to update the default rules with a complete new | |
38d859f9 PM |
439 | * policy. What we do here is to splice ima_policy_rules and ima_temp_rules so |
440 | * they make a queue. The policy may be updated multiple times and this is the | |
441 | * RCU updater. | |
442 | * | |
443 | * Policy rules are never deleted so ima_policy_flag gets zeroed only once when | |
444 | * we switch from the default policy to user defined. | |
4af4662f MZ |
445 | */ |
446 | void ima_update_policy(void) | |
447 | { | |
38d859f9 PM |
448 | struct list_head *first, *last, *policy; |
449 | ||
450 | /* append current policy with the new rules */ | |
451 | first = (&ima_temp_rules)->next; | |
452 | last = (&ima_temp_rules)->prev; | |
453 | policy = &ima_policy_rules; | |
454 | ||
455 | synchronize_rcu(); | |
456 | ||
457 | last->next = policy; | |
458 | rcu_assign_pointer(list_next_rcu(policy->prev), first); | |
459 | first->prev = policy->prev; | |
460 | policy->prev = last; | |
461 | ||
462 | /* prepare for the next policy rules addition */ | |
463 | INIT_LIST_HEAD(&ima_temp_rules); | |
464 | ||
465 | if (ima_rules != policy) { | |
466 | ima_policy_flag = 0; | |
467 | ima_rules = policy; | |
468 | } | |
0716abbb | 469 | ima_update_policy_flag(); |
4af4662f MZ |
470 | } |
471 | ||
472 | enum { | |
473 | Opt_err = -1, | |
474 | Opt_measure = 1, Opt_dont_measure, | |
07f6a794 | 475 | Opt_appraise, Opt_dont_appraise, |
e7c568e0 | 476 | Opt_audit, |
4af4662f MZ |
477 | Opt_obj_user, Opt_obj_role, Opt_obj_type, |
478 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | |
139069ef | 479 | Opt_func, Opt_mask, Opt_fsmagic, |
80eae209 PM |
480 | Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner, |
481 | Opt_appraise_type, Opt_permit_directio | |
4af4662f MZ |
482 | }; |
483 | ||
484 | static match_table_t policy_tokens = { | |
485 | {Opt_measure, "measure"}, | |
486 | {Opt_dont_measure, "dont_measure"}, | |
07f6a794 MZ |
487 | {Opt_appraise, "appraise"}, |
488 | {Opt_dont_appraise, "dont_appraise"}, | |
e7c568e0 | 489 | {Opt_audit, "audit"}, |
4af4662f MZ |
490 | {Opt_obj_user, "obj_user=%s"}, |
491 | {Opt_obj_role, "obj_role=%s"}, | |
492 | {Opt_obj_type, "obj_type=%s"}, | |
493 | {Opt_subj_user, "subj_user=%s"}, | |
494 | {Opt_subj_role, "subj_role=%s"}, | |
495 | {Opt_subj_type, "subj_type=%s"}, | |
496 | {Opt_func, "func=%s"}, | |
497 | {Opt_mask, "mask=%s"}, | |
498 | {Opt_fsmagic, "fsmagic=%s"}, | |
85865c1f | 499 | {Opt_fsuuid, "fsuuid=%s"}, |
4af4662f | 500 | {Opt_uid, "uid=%s"}, |
139069ef | 501 | {Opt_euid, "euid=%s"}, |
07f6a794 | 502 | {Opt_fowner, "fowner=%s"}, |
0e5a247c | 503 | {Opt_appraise_type, "appraise_type=%s"}, |
f9b2a735 | 504 | {Opt_permit_directio, "permit_directio"}, |
4af4662f MZ |
505 | {Opt_err, NULL} |
506 | }; | |
507 | ||
07f6a794 | 508 | static int ima_lsm_rule_init(struct ima_rule_entry *entry, |
7163a993 | 509 | substring_t *args, int lsm_rule, int audit_type) |
4af4662f MZ |
510 | { |
511 | int result; | |
512 | ||
7b62e162 EP |
513 | if (entry->lsm[lsm_rule].rule) |
514 | return -EINVAL; | |
515 | ||
7163a993 MZ |
516 | entry->lsm[lsm_rule].args_p = match_strdup(args); |
517 | if (!entry->lsm[lsm_rule].args_p) | |
518 | return -ENOMEM; | |
519 | ||
4af4662f MZ |
520 | entry->lsm[lsm_rule].type = audit_type; |
521 | result = security_filter_rule_init(entry->lsm[lsm_rule].type, | |
7163a993 MZ |
522 | Audit_equal, |
523 | entry->lsm[lsm_rule].args_p, | |
4af4662f | 524 | &entry->lsm[lsm_rule].rule); |
7163a993 MZ |
525 | if (!entry->lsm[lsm_rule].rule) { |
526 | kfree(entry->lsm[lsm_rule].args_p); | |
867c2026 | 527 | return -EINVAL; |
7163a993 MZ |
528 | } |
529 | ||
4af4662f MZ |
530 | return result; |
531 | } | |
532 | ||
2f1506cd EP |
533 | static void ima_log_string(struct audit_buffer *ab, char *key, char *value) |
534 | { | |
535 | audit_log_format(ab, "%s=", key); | |
536 | audit_log_untrustedstring(ab, value); | |
537 | audit_log_format(ab, " "); | |
538 | } | |
539 | ||
07f6a794 | 540 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) |
4af4662f MZ |
541 | { |
542 | struct audit_buffer *ab; | |
4351c294 | 543 | char *from; |
4af4662f MZ |
544 | char *p; |
545 | int result = 0; | |
546 | ||
523979ad | 547 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); |
4af4662f | 548 | |
8b94eea4 | 549 | entry->uid = INVALID_UID; |
88265322 | 550 | entry->fowner = INVALID_UID; |
b9035b1f | 551 | entry->action = UNKNOWN; |
28ef4002 | 552 | while ((p = strsep(&rule, " \t")) != NULL) { |
4af4662f MZ |
553 | substring_t args[MAX_OPT_ARGS]; |
554 | int token; | |
555 | unsigned long lnum; | |
556 | ||
557 | if (result < 0) | |
558 | break; | |
28ef4002 EP |
559 | if ((*p == '\0') || (*p == ' ') || (*p == '\t')) |
560 | continue; | |
4af4662f MZ |
561 | token = match_token(p, policy_tokens, args); |
562 | switch (token) { | |
563 | case Opt_measure: | |
2f1506cd | 564 | ima_log_string(ab, "action", "measure"); |
7b62e162 EP |
565 | |
566 | if (entry->action != UNKNOWN) | |
567 | result = -EINVAL; | |
568 | ||
4af4662f MZ |
569 | entry->action = MEASURE; |
570 | break; | |
571 | case Opt_dont_measure: | |
2f1506cd | 572 | ima_log_string(ab, "action", "dont_measure"); |
7b62e162 EP |
573 | |
574 | if (entry->action != UNKNOWN) | |
575 | result = -EINVAL; | |
576 | ||
4af4662f MZ |
577 | entry->action = DONT_MEASURE; |
578 | break; | |
07f6a794 MZ |
579 | case Opt_appraise: |
580 | ima_log_string(ab, "action", "appraise"); | |
581 | ||
582 | if (entry->action != UNKNOWN) | |
583 | result = -EINVAL; | |
584 | ||
585 | entry->action = APPRAISE; | |
586 | break; | |
587 | case Opt_dont_appraise: | |
588 | ima_log_string(ab, "action", "dont_appraise"); | |
589 | ||
590 | if (entry->action != UNKNOWN) | |
591 | result = -EINVAL; | |
592 | ||
593 | entry->action = DONT_APPRAISE; | |
594 | break; | |
e7c568e0 PM |
595 | case Opt_audit: |
596 | ima_log_string(ab, "action", "audit"); | |
597 | ||
598 | if (entry->action != UNKNOWN) | |
599 | result = -EINVAL; | |
600 | ||
601 | entry->action = AUDIT; | |
602 | break; | |
4af4662f | 603 | case Opt_func: |
2f1506cd | 604 | ima_log_string(ab, "func", args[0].from); |
7b62e162 EP |
605 | |
606 | if (entry->func) | |
07f6a794 | 607 | result = -EINVAL; |
7b62e162 | 608 | |
1e93d005 MZ |
609 | if (strcmp(args[0].from, "FILE_CHECK") == 0) |
610 | entry->func = FILE_CHECK; | |
611 | /* PATH_CHECK is for backwards compat */ | |
612 | else if (strcmp(args[0].from, "PATH_CHECK") == 0) | |
613 | entry->func = FILE_CHECK; | |
fdf90729 MZ |
614 | else if (strcmp(args[0].from, "MODULE_CHECK") == 0) |
615 | entry->func = MODULE_CHECK; | |
5a9196d7 MZ |
616 | else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0) |
617 | entry->func = FIRMWARE_CHECK; | |
16cac49f MZ |
618 | else if ((strcmp(args[0].from, "FILE_MMAP") == 0) |
619 | || (strcmp(args[0].from, "MMAP_CHECK") == 0)) | |
620 | entry->func = MMAP_CHECK; | |
4af4662f MZ |
621 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) |
622 | entry->func = BPRM_CHECK; | |
d9ddf077 MZ |
623 | else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") == |
624 | 0) | |
625 | entry->func = KEXEC_KERNEL_CHECK; | |
626 | else if (strcmp(args[0].from, "KEXEC_INITRAMFS_CHECK") | |
627 | == 0) | |
628 | entry->func = KEXEC_INITRAMFS_CHECK; | |
19f8a847 MZ |
629 | else if (strcmp(args[0].from, "POLICY_CHECK") == 0) |
630 | entry->func = POLICY_CHECK; | |
4af4662f MZ |
631 | else |
632 | result = -EINVAL; | |
633 | if (!result) | |
634 | entry->flags |= IMA_FUNC; | |
635 | break; | |
636 | case Opt_mask: | |
2f1506cd | 637 | ima_log_string(ab, "mask", args[0].from); |
7b62e162 EP |
638 | |
639 | if (entry->mask) | |
640 | result = -EINVAL; | |
641 | ||
4351c294 MZ |
642 | from = args[0].from; |
643 | if (*from == '^') | |
644 | from++; | |
645 | ||
646 | if ((strcmp(from, "MAY_EXEC")) == 0) | |
4af4662f | 647 | entry->mask = MAY_EXEC; |
4351c294 | 648 | else if (strcmp(from, "MAY_WRITE") == 0) |
4af4662f | 649 | entry->mask = MAY_WRITE; |
4351c294 | 650 | else if (strcmp(from, "MAY_READ") == 0) |
4af4662f | 651 | entry->mask = MAY_READ; |
4351c294 | 652 | else if (strcmp(from, "MAY_APPEND") == 0) |
4af4662f MZ |
653 | entry->mask = MAY_APPEND; |
654 | else | |
655 | result = -EINVAL; | |
656 | if (!result) | |
4351c294 MZ |
657 | entry->flags |= (*args[0].from == '^') |
658 | ? IMA_INMASK : IMA_MASK; | |
4af4662f MZ |
659 | break; |
660 | case Opt_fsmagic: | |
2f1506cd | 661 | ima_log_string(ab, "fsmagic", args[0].from); |
7b62e162 EP |
662 | |
663 | if (entry->fsmagic) { | |
664 | result = -EINVAL; | |
665 | break; | |
666 | } | |
667 | ||
2bb930ab | 668 | result = kstrtoul(args[0].from, 16, &entry->fsmagic); |
4af4662f MZ |
669 | if (!result) |
670 | entry->flags |= IMA_FSMAGIC; | |
671 | break; | |
85865c1f DK |
672 | case Opt_fsuuid: |
673 | ima_log_string(ab, "fsuuid", args[0].from); | |
674 | ||
675 | if (memchr_inv(entry->fsuuid, 0x00, | |
446d64e3 | 676 | sizeof(entry->fsuuid))) { |
85865c1f DK |
677 | result = -EINVAL; |
678 | break; | |
679 | } | |
680 | ||
446d64e3 MZ |
681 | result = blk_part_pack_uuid(args[0].from, |
682 | entry->fsuuid); | |
683 | if (!result) | |
684 | entry->flags |= IMA_FSUUID; | |
85865c1f | 685 | break; |
4af4662f | 686 | case Opt_uid: |
2f1506cd | 687 | ima_log_string(ab, "uid", args[0].from); |
139069ef MZ |
688 | case Opt_euid: |
689 | if (token == Opt_euid) | |
690 | ima_log_string(ab, "euid", args[0].from); | |
7b62e162 | 691 | |
8b94eea4 | 692 | if (uid_valid(entry->uid)) { |
7b62e162 EP |
693 | result = -EINVAL; |
694 | break; | |
695 | } | |
696 | ||
29707b20 | 697 | result = kstrtoul(args[0].from, 10, &lnum); |
4af4662f | 698 | if (!result) { |
139069ef MZ |
699 | entry->uid = make_kuid(current_user_ns(), |
700 | (uid_t) lnum); | |
701 | if (!uid_valid(entry->uid) || | |
702 | (uid_t)lnum != lnum) | |
4af4662f MZ |
703 | result = -EINVAL; |
704 | else | |
139069ef MZ |
705 | entry->flags |= (token == Opt_uid) |
706 | ? IMA_UID : IMA_EUID; | |
4af4662f MZ |
707 | } |
708 | break; | |
07f6a794 MZ |
709 | case Opt_fowner: |
710 | ima_log_string(ab, "fowner", args[0].from); | |
711 | ||
88265322 | 712 | if (uid_valid(entry->fowner)) { |
07f6a794 MZ |
713 | result = -EINVAL; |
714 | break; | |
715 | } | |
716 | ||
29707b20 | 717 | result = kstrtoul(args[0].from, 10, &lnum); |
07f6a794 | 718 | if (!result) { |
88265322 LT |
719 | entry->fowner = make_kuid(current_user_ns(), (uid_t)lnum); |
720 | if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum)) | |
07f6a794 MZ |
721 | result = -EINVAL; |
722 | else | |
723 | entry->flags |= IMA_FOWNER; | |
724 | } | |
725 | break; | |
4af4662f | 726 | case Opt_obj_user: |
2f1506cd | 727 | ima_log_string(ab, "obj_user", args[0].from); |
7163a993 | 728 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
729 | LSM_OBJ_USER, |
730 | AUDIT_OBJ_USER); | |
731 | break; | |
732 | case Opt_obj_role: | |
2f1506cd | 733 | ima_log_string(ab, "obj_role", args[0].from); |
7163a993 | 734 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
735 | LSM_OBJ_ROLE, |
736 | AUDIT_OBJ_ROLE); | |
737 | break; | |
738 | case Opt_obj_type: | |
2f1506cd | 739 | ima_log_string(ab, "obj_type", args[0].from); |
7163a993 | 740 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
741 | LSM_OBJ_TYPE, |
742 | AUDIT_OBJ_TYPE); | |
743 | break; | |
744 | case Opt_subj_user: | |
2f1506cd | 745 | ima_log_string(ab, "subj_user", args[0].from); |
7163a993 | 746 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
747 | LSM_SUBJ_USER, |
748 | AUDIT_SUBJ_USER); | |
749 | break; | |
750 | case Opt_subj_role: | |
2f1506cd | 751 | ima_log_string(ab, "subj_role", args[0].from); |
7163a993 | 752 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
753 | LSM_SUBJ_ROLE, |
754 | AUDIT_SUBJ_ROLE); | |
755 | break; | |
756 | case Opt_subj_type: | |
2f1506cd | 757 | ima_log_string(ab, "subj_type", args[0].from); |
7163a993 | 758 | result = ima_lsm_rule_init(entry, args, |
4af4662f MZ |
759 | LSM_SUBJ_TYPE, |
760 | AUDIT_SUBJ_TYPE); | |
761 | break; | |
0e5a247c DK |
762 | case Opt_appraise_type: |
763 | if (entry->action != APPRAISE) { | |
764 | result = -EINVAL; | |
765 | break; | |
766 | } | |
767 | ||
768 | ima_log_string(ab, "appraise_type", args[0].from); | |
769 | if ((strcmp(args[0].from, "imasig")) == 0) | |
770 | entry->flags |= IMA_DIGSIG_REQUIRED; | |
771 | else | |
772 | result = -EINVAL; | |
773 | break; | |
f9b2a735 MZ |
774 | case Opt_permit_directio: |
775 | entry->flags |= IMA_PERMIT_DIRECTIO; | |
776 | break; | |
4af4662f | 777 | case Opt_err: |
2f1506cd | 778 | ima_log_string(ab, "UNKNOWN", p); |
e9d393bf | 779 | result = -EINVAL; |
4af4662f MZ |
780 | break; |
781 | } | |
782 | } | |
7b62e162 | 783 | if (!result && (entry->action == UNKNOWN)) |
4af4662f | 784 | result = -EINVAL; |
a7f2a366 | 785 | else if (entry->func == MODULE_CHECK) |
6ad6afa1 | 786 | temp_ima_appraise |= IMA_APPRAISE_MODULES; |
5a9196d7 | 787 | else if (entry->func == FIRMWARE_CHECK) |
6ad6afa1 | 788 | temp_ima_appraise |= IMA_APPRAISE_FIRMWARE; |
19f8a847 MZ |
789 | else if (entry->func == POLICY_CHECK) |
790 | temp_ima_appraise |= IMA_APPRAISE_POLICY; | |
b0d5de4d | 791 | audit_log_format(ab, "res=%d", !result); |
4af4662f MZ |
792 | audit_log_end(ab); |
793 | return result; | |
794 | } | |
795 | ||
796 | /** | |
07f6a794 | 797 | * ima_parse_add_rule - add a rule to ima_policy_rules |
4af4662f MZ |
798 | * @rule - ima measurement policy rule |
799 | * | |
38d859f9 | 800 | * Avoid locking by allowing just one writer at a time in ima_write_policy() |
6ccd0456 | 801 | * Returns the length of the rule parsed, an error code on failure |
4af4662f | 802 | */ |
6ccd0456 | 803 | ssize_t ima_parse_add_rule(char *rule) |
4af4662f | 804 | { |
52a13284 | 805 | static const char op[] = "update_policy"; |
6ccd0456 | 806 | char *p; |
07f6a794 | 807 | struct ima_rule_entry *entry; |
6ccd0456 | 808 | ssize_t result, len; |
4af4662f MZ |
809 | int audit_info = 0; |
810 | ||
272a6e90 DK |
811 | p = strsep(&rule, "\n"); |
812 | len = strlen(p) + 1; | |
7178784f | 813 | p += strspn(p, " \t"); |
272a6e90 | 814 | |
7178784f | 815 | if (*p == '#' || *p == '\0') |
272a6e90 DK |
816 | return len; |
817 | ||
4af4662f MZ |
818 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
819 | if (!entry) { | |
820 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | |
821 | NULL, op, "-ENOMEM", -ENOMEM, audit_info); | |
822 | return -ENOMEM; | |
823 | } | |
824 | ||
825 | INIT_LIST_HEAD(&entry->list); | |
826 | ||
6ccd0456 | 827 | result = ima_parse_rule(p, entry); |
7233e3ee | 828 | if (result) { |
4af4662f | 829 | kfree(entry); |
523979ad | 830 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
7e9001f6 | 831 | NULL, op, "invalid-policy", result, |
523979ad | 832 | audit_info); |
7233e3ee | 833 | return result; |
523979ad | 834 | } |
7233e3ee | 835 | |
38d859f9 | 836 | list_add_tail(&entry->list, &ima_temp_rules); |
7233e3ee EP |
837 | |
838 | return len; | |
4af4662f MZ |
839 | } |
840 | ||
38d859f9 PM |
841 | /** |
842 | * ima_delete_rules() called to cleanup invalid in-flight policy. | |
843 | * We don't need locking as we operate on the temp list, which is | |
844 | * different from the active one. There is also only one user of | |
845 | * ima_delete_rules() at a time. | |
846 | */ | |
64c61d80 | 847 | void ima_delete_rules(void) |
4af4662f | 848 | { |
07f6a794 | 849 | struct ima_rule_entry *entry, *tmp; |
7163a993 | 850 | int i; |
4af4662f | 851 | |
6ad6afa1 | 852 | temp_ima_appraise = 0; |
38d859f9 | 853 | list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) { |
7163a993 MZ |
854 | for (i = 0; i < MAX_LSM_RULES; i++) |
855 | kfree(entry->lsm[i].args_p); | |
856 | ||
4af4662f MZ |
857 | list_del(&entry->list); |
858 | kfree(entry); | |
859 | } | |
4af4662f | 860 | } |
80eae209 PM |
861 | |
862 | #ifdef CONFIG_IMA_READ_POLICY | |
863 | enum { | |
864 | mask_exec = 0, mask_write, mask_read, mask_append | |
865 | }; | |
866 | ||
867 | static char *mask_tokens[] = { | |
868 | "MAY_EXEC", | |
869 | "MAY_WRITE", | |
870 | "MAY_READ", | |
871 | "MAY_APPEND" | |
872 | }; | |
873 | ||
874 | enum { | |
875 | func_file = 0, func_mmap, func_bprm, | |
d9ddf077 | 876 | func_module, func_firmware, func_post, |
19f8a847 MZ |
877 | func_kexec_kernel, func_kexec_initramfs, |
878 | func_policy | |
80eae209 PM |
879 | }; |
880 | ||
881 | static char *func_tokens[] = { | |
882 | "FILE_CHECK", | |
883 | "MMAP_CHECK", | |
884 | "BPRM_CHECK", | |
885 | "MODULE_CHECK", | |
886 | "FIRMWARE_CHECK", | |
cf90ea93 | 887 | "POST_SETATTR", |
d9ddf077 MZ |
888 | "KEXEC_KERNEL_CHECK", |
889 | "KEXEC_INITRAMFS_CHECK", | |
cf90ea93 | 890 | "POLICY_CHECK" |
80eae209 PM |
891 | }; |
892 | ||
893 | void *ima_policy_start(struct seq_file *m, loff_t *pos) | |
894 | { | |
895 | loff_t l = *pos; | |
896 | struct ima_rule_entry *entry; | |
897 | ||
898 | rcu_read_lock(); | |
899 | list_for_each_entry_rcu(entry, ima_rules, list) { | |
900 | if (!l--) { | |
901 | rcu_read_unlock(); | |
902 | return entry; | |
903 | } | |
904 | } | |
905 | rcu_read_unlock(); | |
906 | return NULL; | |
907 | } | |
908 | ||
909 | void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) | |
910 | { | |
911 | struct ima_rule_entry *entry = v; | |
912 | ||
913 | rcu_read_lock(); | |
914 | entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list); | |
915 | rcu_read_unlock(); | |
916 | (*pos)++; | |
917 | ||
918 | return (&entry->list == ima_rules) ? NULL : entry; | |
919 | } | |
920 | ||
921 | void ima_policy_stop(struct seq_file *m, void *v) | |
922 | { | |
923 | } | |
924 | ||
925 | #define pt(token) policy_tokens[token + Opt_err].pattern | |
926 | #define mt(token) mask_tokens[token] | |
927 | #define ft(token) func_tokens[token] | |
928 | ||
b5269ab3 MZ |
929 | /* |
930 | * policy_func_show - display the ima_hooks policy rule | |
931 | */ | |
932 | static void policy_func_show(struct seq_file *m, enum ima_hooks func) | |
933 | { | |
934 | char tbuf[64] = {0,}; | |
935 | ||
936 | switch (func) { | |
937 | case FILE_CHECK: | |
938 | seq_printf(m, pt(Opt_func), ft(func_file)); | |
939 | break; | |
940 | case MMAP_CHECK: | |
941 | seq_printf(m, pt(Opt_func), ft(func_mmap)); | |
942 | break; | |
943 | case BPRM_CHECK: | |
944 | seq_printf(m, pt(Opt_func), ft(func_bprm)); | |
945 | break; | |
946 | case MODULE_CHECK: | |
947 | seq_printf(m, pt(Opt_func), ft(func_module)); | |
948 | break; | |
949 | case FIRMWARE_CHECK: | |
950 | seq_printf(m, pt(Opt_func), ft(func_firmware)); | |
951 | break; | |
952 | case POST_SETATTR: | |
953 | seq_printf(m, pt(Opt_func), ft(func_post)); | |
954 | break; | |
d9ddf077 MZ |
955 | case KEXEC_KERNEL_CHECK: |
956 | seq_printf(m, pt(Opt_func), ft(func_kexec_kernel)); | |
957 | break; | |
958 | case KEXEC_INITRAMFS_CHECK: | |
959 | seq_printf(m, pt(Opt_func), ft(func_kexec_initramfs)); | |
960 | break; | |
19f8a847 MZ |
961 | case POLICY_CHECK: |
962 | seq_printf(m, pt(Opt_func), ft(func_policy)); | |
963 | break; | |
b5269ab3 MZ |
964 | default: |
965 | snprintf(tbuf, sizeof(tbuf), "%d", func); | |
966 | seq_printf(m, pt(Opt_func), tbuf); | |
967 | break; | |
968 | } | |
969 | seq_puts(m, " "); | |
970 | } | |
971 | ||
80eae209 PM |
972 | int ima_policy_show(struct seq_file *m, void *v) |
973 | { | |
974 | struct ima_rule_entry *entry = v; | |
b8b57278 | 975 | int i; |
80eae209 PM |
976 | char tbuf[64] = {0,}; |
977 | ||
978 | rcu_read_lock(); | |
979 | ||
980 | if (entry->action & MEASURE) | |
981 | seq_puts(m, pt(Opt_measure)); | |
982 | if (entry->action & DONT_MEASURE) | |
983 | seq_puts(m, pt(Opt_dont_measure)); | |
984 | if (entry->action & APPRAISE) | |
985 | seq_puts(m, pt(Opt_appraise)); | |
986 | if (entry->action & DONT_APPRAISE) | |
987 | seq_puts(m, pt(Opt_dont_appraise)); | |
988 | if (entry->action & AUDIT) | |
989 | seq_puts(m, pt(Opt_audit)); | |
990 | ||
991 | seq_puts(m, " "); | |
992 | ||
b5269ab3 MZ |
993 | if (entry->flags & IMA_FUNC) |
994 | policy_func_show(m, entry->func); | |
80eae209 PM |
995 | |
996 | if (entry->flags & IMA_MASK) { | |
997 | if (entry->mask & MAY_EXEC) | |
998 | seq_printf(m, pt(Opt_mask), mt(mask_exec)); | |
999 | if (entry->mask & MAY_WRITE) | |
1000 | seq_printf(m, pt(Opt_mask), mt(mask_write)); | |
1001 | if (entry->mask & MAY_READ) | |
1002 | seq_printf(m, pt(Opt_mask), mt(mask_read)); | |
1003 | if (entry->mask & MAY_APPEND) | |
1004 | seq_printf(m, pt(Opt_mask), mt(mask_append)); | |
1005 | seq_puts(m, " "); | |
1006 | } | |
1007 | ||
1008 | if (entry->flags & IMA_FSMAGIC) { | |
1009 | snprintf(tbuf, sizeof(tbuf), "0x%lx", entry->fsmagic); | |
1010 | seq_printf(m, pt(Opt_fsmagic), tbuf); | |
1011 | seq_puts(m, " "); | |
1012 | } | |
1013 | ||
1014 | if (entry->flags & IMA_FSUUID) { | |
b8b57278 | 1015 | seq_printf(m, "fsuuid=%pU", entry->fsuuid); |
80eae209 PM |
1016 | seq_puts(m, " "); |
1017 | } | |
1018 | ||
1019 | if (entry->flags & IMA_UID) { | |
1020 | snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); | |
1021 | seq_printf(m, pt(Opt_uid), tbuf); | |
1022 | seq_puts(m, " "); | |
1023 | } | |
1024 | ||
1025 | if (entry->flags & IMA_EUID) { | |
1026 | snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); | |
1027 | seq_printf(m, pt(Opt_euid), tbuf); | |
1028 | seq_puts(m, " "); | |
1029 | } | |
1030 | ||
1031 | if (entry->flags & IMA_FOWNER) { | |
1032 | snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); | |
1033 | seq_printf(m, pt(Opt_fowner), tbuf); | |
1034 | seq_puts(m, " "); | |
1035 | } | |
1036 | ||
1037 | for (i = 0; i < MAX_LSM_RULES; i++) { | |
1038 | if (entry->lsm[i].rule) { | |
1039 | switch (i) { | |
1040 | case LSM_OBJ_USER: | |
1041 | seq_printf(m, pt(Opt_obj_user), | |
1042 | (char *)entry->lsm[i].args_p); | |
1043 | break; | |
1044 | case LSM_OBJ_ROLE: | |
1045 | seq_printf(m, pt(Opt_obj_role), | |
1046 | (char *)entry->lsm[i].args_p); | |
1047 | break; | |
1048 | case LSM_OBJ_TYPE: | |
1049 | seq_printf(m, pt(Opt_obj_type), | |
1050 | (char *)entry->lsm[i].args_p); | |
1051 | break; | |
1052 | case LSM_SUBJ_USER: | |
1053 | seq_printf(m, pt(Opt_subj_user), | |
1054 | (char *)entry->lsm[i].args_p); | |
1055 | break; | |
1056 | case LSM_SUBJ_ROLE: | |
1057 | seq_printf(m, pt(Opt_subj_role), | |
1058 | (char *)entry->lsm[i].args_p); | |
1059 | break; | |
1060 | case LSM_SUBJ_TYPE: | |
1061 | seq_printf(m, pt(Opt_subj_type), | |
1062 | (char *)entry->lsm[i].args_p); | |
1063 | break; | |
1064 | } | |
1065 | } | |
1066 | } | |
1067 | if (entry->flags & IMA_DIGSIG_REQUIRED) | |
1068 | seq_puts(m, "appraise_type=imasig "); | |
1069 | if (entry->flags & IMA_PERMIT_DIRECTIO) | |
1070 | seq_puts(m, "permit_directio "); | |
1071 | rcu_read_unlock(); | |
1072 | seq_puts(m, "\n"); | |
1073 | return 0; | |
1074 | } | |
1075 | #endif /* CONFIG_IMA_READ_POLICY */ |