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