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