diff options
Diffstat (limited to 'security/integrity')
-rw-r--r-- | security/integrity/ima/Kconfig | 6 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 24 | ||||
-rw-r--r-- | security/integrity/ima/ima_fs.c | 67 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 293 |
4 files changed, 386 insertions, 4 deletions
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 2a761c8ac996..3d2b6ee778a0 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
@@ -47,3 +47,9 @@ config IMA_AUDIT | |||
47 | auditing messages can be enabled with 'ima_audit=1' on | 47 | auditing messages can be enabled with 'ima_audit=1' on |
48 | the kernel command line. | 48 | the kernel command line. |
49 | 49 | ||
50 | config IMA_LSM_RULES | ||
51 | bool | ||
52 | depends on IMA && (SECURITY_SELINUX || SECURITY_SMACK) | ||
53 | default y | ||
54 | help | ||
55 | Disabling this option will disregard LSM based policy rules | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 9c280cc73004..42706b554921 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -137,4 +137,28 @@ enum ima_hooks { PATH_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | |||
137 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | 137 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); |
138 | void ima_init_policy(void); | 138 | void ima_init_policy(void); |
139 | void ima_update_policy(void); | 139 | void ima_update_policy(void); |
140 | int ima_parse_add_rule(char *); | ||
141 | void ima_delete_rules(void); | ||
142 | |||
143 | /* LSM based policy rules require audit */ | ||
144 | #ifdef CONFIG_IMA_LSM_RULES | ||
145 | |||
146 | #define security_filter_rule_init security_audit_rule_init | ||
147 | #define security_filter_rule_match security_audit_rule_match | ||
148 | |||
149 | #else | ||
150 | |||
151 | static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr, | ||
152 | void **lsmrule) | ||
153 | { | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | static inline int security_filter_rule_match(u32 secid, u32 field, u32 op, | ||
158 | void *lsmrule, | ||
159 | struct audit_context *actx) | ||
160 | { | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | #endif /* CONFIG_IMA_LSM_RULES */ | ||
140 | #endif | 164 | #endif |
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 4f25be768b50..95ef1caa64b5 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
@@ -19,9 +19,11 @@ | |||
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | #include <linux/rculist.h> | 20 | #include <linux/rculist.h> |
21 | #include <linux/rcupdate.h> | 21 | #include <linux/rcupdate.h> |
22 | #include <linux/parser.h> | ||
22 | 23 | ||
23 | #include "ima.h" | 24 | #include "ima.h" |
24 | 25 | ||
26 | static int valid_policy = 1; | ||
25 | #define TMPBUFLEN 12 | 27 | #define TMPBUFLEN 12 |
26 | static ssize_t ima_show_htable_value(char __user *buf, size_t count, | 28 | static ssize_t ima_show_htable_value(char __user *buf, size_t count, |
27 | loff_t *ppos, atomic_long_t *val) | 29 | loff_t *ppos, atomic_long_t *val) |
@@ -237,11 +239,66 @@ static struct file_operations ima_ascii_measurements_ops = { | |||
237 | .release = seq_release, | 239 | .release = seq_release, |
238 | }; | 240 | }; |
239 | 241 | ||
242 | static ssize_t ima_write_policy(struct file *file, const char __user *buf, | ||
243 | size_t datalen, loff_t *ppos) | ||
244 | { | ||
245 | char *data; | ||
246 | int rc; | ||
247 | |||
248 | if (datalen >= PAGE_SIZE) | ||
249 | return -ENOMEM; | ||
250 | if (*ppos != 0) { | ||
251 | /* No partial writes. */ | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | data = kmalloc(datalen + 1, GFP_KERNEL); | ||
255 | if (!data) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | if (copy_from_user(data, buf, datalen)) { | ||
259 | kfree(data); | ||
260 | return -EFAULT; | ||
261 | } | ||
262 | *(data + datalen) = '\0'; | ||
263 | rc = ima_parse_add_rule(data); | ||
264 | if (rc < 0) { | ||
265 | datalen = -EINVAL; | ||
266 | valid_policy = 0; | ||
267 | } | ||
268 | |||
269 | kfree(data); | ||
270 | return datalen; | ||
271 | } | ||
272 | |||
240 | static struct dentry *ima_dir; | 273 | static struct dentry *ima_dir; |
241 | static struct dentry *binary_runtime_measurements; | 274 | static struct dentry *binary_runtime_measurements; |
242 | static struct dentry *ascii_runtime_measurements; | 275 | static struct dentry *ascii_runtime_measurements; |
243 | static struct dentry *runtime_measurements_count; | 276 | static struct dentry *runtime_measurements_count; |
244 | static struct dentry *violations; | 277 | static struct dentry *violations; |
278 | static struct dentry *ima_policy; | ||
279 | |||
280 | /* | ||
281 | * ima_release_policy - start using the new measure policy rules. | ||
282 | * | ||
283 | * Initially, ima_measure points to the default policy rules, now | ||
284 | * point to the new policy rules, and remove the securityfs policy file. | ||
285 | */ | ||
286 | static int ima_release_policy(struct inode *inode, struct file *file) | ||
287 | { | ||
288 | if (!valid_policy) { | ||
289 | ima_delete_rules(); | ||
290 | return 0; | ||
291 | } | ||
292 | ima_update_policy(); | ||
293 | securityfs_remove(ima_policy); | ||
294 | ima_policy = NULL; | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static struct file_operations ima_measure_policy_ops = { | ||
299 | .write = ima_write_policy, | ||
300 | .release = ima_release_policy | ||
301 | }; | ||
245 | 302 | ||
246 | int ima_fs_init(void) | 303 | int ima_fs_init(void) |
247 | { | 304 | { |
@@ -276,13 +333,20 @@ int ima_fs_init(void) | |||
276 | if (IS_ERR(violations)) | 333 | if (IS_ERR(violations)) |
277 | goto out; | 334 | goto out; |
278 | 335 | ||
279 | return 0; | 336 | ima_policy = securityfs_create_file("policy", |
337 | S_IRUSR | S_IRGRP | S_IWUSR, | ||
338 | ima_dir, NULL, | ||
339 | &ima_measure_policy_ops); | ||
340 | if (IS_ERR(ima_policy)) | ||
341 | goto out; | ||
280 | 342 | ||
343 | return 0; | ||
281 | out: | 344 | out: |
282 | securityfs_remove(runtime_measurements_count); | 345 | securityfs_remove(runtime_measurements_count); |
283 | securityfs_remove(ascii_runtime_measurements); | 346 | securityfs_remove(ascii_runtime_measurements); |
284 | securityfs_remove(binary_runtime_measurements); | 347 | securityfs_remove(binary_runtime_measurements); |
285 | securityfs_remove(ima_dir); | 348 | securityfs_remove(ima_dir); |
349 | securityfs_remove(ima_policy); | ||
286 | return -1; | 350 | return -1; |
287 | } | 351 | } |
288 | 352 | ||
@@ -293,4 +357,5 @@ void __exit ima_fs_cleanup(void) | |||
293 | securityfs_remove(ascii_runtime_measurements); | 357 | securityfs_remove(ascii_runtime_measurements); |
294 | securityfs_remove(binary_runtime_measurements); | 358 | securityfs_remove(binary_runtime_measurements); |
295 | securityfs_remove(ima_dir); | 359 | securityfs_remove(ima_dir); |
360 | securityfs_remove(ima_policy); | ||
296 | } | 361 | } |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 7c3d1ffb1472..bd453603e2c3 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/audit.h> | 15 | #include <linux/audit.h> |
16 | #include <linux/security.h> | 16 | #include <linux/security.h> |
17 | #include <linux/magic.h> | 17 | #include <linux/magic.h> |
18 | #include <linux/parser.h> | ||
18 | 19 | ||
19 | #include "ima.h" | 20 | #include "ima.h" |
20 | 21 | ||
@@ -24,7 +25,12 @@ | |||
24 | #define IMA_FSMAGIC 0x0004 | 25 | #define IMA_FSMAGIC 0x0004 |
25 | #define IMA_UID 0x0008 | 26 | #define IMA_UID 0x0008 |
26 | 27 | ||
27 | enum ima_action { DONT_MEASURE, MEASURE }; | 28 | enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE }; |
29 | |||
30 | #define MAX_LSM_RULES 6 | ||
31 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | ||
32 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE | ||
33 | }; | ||
28 | 34 | ||
29 | struct ima_measure_rule_entry { | 35 | struct ima_measure_rule_entry { |
30 | struct list_head list; | 36 | struct list_head list; |
@@ -34,8 +40,15 @@ struct ima_measure_rule_entry { | |||
34 | int mask; | 40 | int mask; |
35 | unsigned long fsmagic; | 41 | unsigned long fsmagic; |
36 | uid_t uid; | 42 | uid_t uid; |
43 | struct { | ||
44 | void *rule; /* LSM file metadata specific */ | ||
45 | int type; /* audit type */ | ||
46 | } lsm[MAX_LSM_RULES]; | ||
37 | }; | 47 | }; |
38 | 48 | ||
49 | /* Without LSM specific knowledge, the default policy can only be | ||
50 | * written in terms of .action, .func, .mask, .fsmagic, and .uid | ||
51 | */ | ||
39 | static struct ima_measure_rule_entry default_rules[] = { | 52 | static struct ima_measure_rule_entry default_rules[] = { |
40 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC, | 53 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC, |
41 | .flags = IMA_FSMAGIC}, | 54 | .flags = IMA_FSMAGIC}, |
@@ -54,8 +67,11 @@ static struct ima_measure_rule_entry default_rules[] = { | |||
54 | }; | 67 | }; |
55 | 68 | ||
56 | static LIST_HEAD(measure_default_rules); | 69 | static LIST_HEAD(measure_default_rules); |
70 | static LIST_HEAD(measure_policy_rules); | ||
57 | static struct list_head *ima_measure; | 71 | static struct list_head *ima_measure; |
58 | 72 | ||
73 | static DEFINE_MUTEX(ima_measure_mutex); | ||
74 | |||
59 | /** | 75 | /** |
60 | * ima_match_rules - determine whether an inode matches the measure rule. | 76 | * ima_match_rules - determine whether an inode matches the measure rule. |
61 | * @rule: a pointer to a rule | 77 | * @rule: a pointer to a rule |
@@ -69,6 +85,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
69 | struct inode *inode, enum ima_hooks func, int mask) | 85 | struct inode *inode, enum ima_hooks func, int mask) |
70 | { | 86 | { |
71 | struct task_struct *tsk = current; | 87 | struct task_struct *tsk = current; |
88 | int i; | ||
72 | 89 | ||
73 | if ((rule->flags & IMA_FUNC) && rule->func != func) | 90 | if ((rule->flags & IMA_FUNC) && rule->func != func) |
74 | return false; | 91 | return false; |
@@ -79,6 +96,39 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
79 | return false; | 96 | return false; |
80 | if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) | 97 | if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) |
81 | return false; | 98 | return false; |
99 | for (i = 0; i < MAX_LSM_RULES; i++) { | ||
100 | int rc; | ||
101 | u32 osid, sid; | ||
102 | |||
103 | if (!rule->lsm[i].rule) | ||
104 | continue; | ||
105 | |||
106 | switch (i) { | ||
107 | case LSM_OBJ_USER: | ||
108 | case LSM_OBJ_ROLE: | ||
109 | case LSM_OBJ_TYPE: | ||
110 | security_inode_getsecid(inode, &osid); | ||
111 | rc = security_filter_rule_match(osid, | ||
112 | rule->lsm[i].type, | ||
113 | AUDIT_EQUAL, | ||
114 | rule->lsm[i].rule, | ||
115 | NULL); | ||
116 | break; | ||
117 | case LSM_SUBJ_USER: | ||
118 | case LSM_SUBJ_ROLE: | ||
119 | case LSM_SUBJ_TYPE: | ||
120 | security_task_getsecid(tsk, &sid); | ||
121 | rc = security_filter_rule_match(sid, | ||
122 | rule->lsm[i].type, | ||
123 | AUDIT_EQUAL, | ||
124 | rule->lsm[i].rule, | ||
125 | NULL); | ||
126 | default: | ||
127 | break; | ||
128 | } | ||
129 | if (!rc) | ||
130 | return false; | ||
131 | } | ||
82 | return true; | 132 | return true; |
83 | } | 133 | } |
84 | 134 | ||
@@ -112,9 +162,8 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask) | |||
112 | /** | 162 | /** |
113 | * ima_init_policy - initialize the default measure rules. | 163 | * ima_init_policy - initialize the default measure rules. |
114 | * | 164 | * |
115 | * (Could use the default_rules directly, but in policy patch | ||
116 | * ima_measure points to either the measure_default_rules or the | 165 | * ima_measure points to either the measure_default_rules or the |
117 | * the new measure_policy_rules.) | 166 | * the new measure_policy_rules. |
118 | */ | 167 | */ |
119 | void ima_init_policy(void) | 168 | void ima_init_policy(void) |
120 | { | 169 | { |
@@ -124,3 +173,241 @@ void ima_init_policy(void) | |||
124 | list_add_tail(&default_rules[i].list, &measure_default_rules); | 173 | list_add_tail(&default_rules[i].list, &measure_default_rules); |
125 | ima_measure = &measure_default_rules; | 174 | ima_measure = &measure_default_rules; |
126 | } | 175 | } |
176 | |||
177 | /** | ||
178 | * ima_update_policy - update default_rules with new measure rules | ||
179 | * | ||
180 | * Called on file .release to update the default rules with a complete new | ||
181 | * policy. Once updated, the policy is locked, no additional rules can be | ||
182 | * added to the policy. | ||
183 | */ | ||
184 | void ima_update_policy(void) | ||
185 | { | ||
186 | const char *op = "policy_update"; | ||
187 | const char *cause = "already exists"; | ||
188 | int result = 1; | ||
189 | int audit_info = 0; | ||
190 | |||
191 | if (ima_measure == &measure_default_rules) { | ||
192 | ima_measure = &measure_policy_rules; | ||
193 | cause = "complete"; | ||
194 | result = 0; | ||
195 | } | ||
196 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
197 | NULL, op, cause, result, audit_info); | ||
198 | } | ||
199 | |||
200 | enum { | ||
201 | Opt_err = -1, | ||
202 | Opt_measure = 1, Opt_dont_measure, | ||
203 | Opt_obj_user, Opt_obj_role, Opt_obj_type, | ||
204 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | ||
205 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid | ||
206 | }; | ||
207 | |||
208 | static match_table_t policy_tokens = { | ||
209 | {Opt_measure, "measure"}, | ||
210 | {Opt_dont_measure, "dont_measure"}, | ||
211 | {Opt_obj_user, "obj_user=%s"}, | ||
212 | {Opt_obj_role, "obj_role=%s"}, | ||
213 | {Opt_obj_type, "obj_type=%s"}, | ||
214 | {Opt_subj_user, "subj_user=%s"}, | ||
215 | {Opt_subj_role, "subj_role=%s"}, | ||
216 | {Opt_subj_type, "subj_type=%s"}, | ||
217 | {Opt_func, "func=%s"}, | ||
218 | {Opt_mask, "mask=%s"}, | ||
219 | {Opt_fsmagic, "fsmagic=%s"}, | ||
220 | {Opt_uid, "uid=%s"}, | ||
221 | {Opt_err, NULL} | ||
222 | }; | ||
223 | |||
224 | static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, | ||
225 | char *args, int lsm_rule, int audit_type) | ||
226 | { | ||
227 | int result; | ||
228 | |||
229 | entry->lsm[lsm_rule].type = audit_type; | ||
230 | result = security_filter_rule_init(entry->lsm[lsm_rule].type, | ||
231 | AUDIT_EQUAL, args, | ||
232 | &entry->lsm[lsm_rule].rule); | ||
233 | return result; | ||
234 | } | ||
235 | |||
236 | static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | ||
237 | { | ||
238 | struct audit_buffer *ab; | ||
239 | char *p; | ||
240 | int result = 0; | ||
241 | |||
242 | ab = audit_log_start(current->audit_context, GFP_KERNEL, | ||
243 | AUDIT_INTEGRITY_STATUS); | ||
244 | |||
245 | entry->action = -1; | ||
246 | while ((p = strsep(&rule, " \n")) != NULL) { | ||
247 | substring_t args[MAX_OPT_ARGS]; | ||
248 | int token; | ||
249 | unsigned long lnum; | ||
250 | |||
251 | if (result < 0) | ||
252 | break; | ||
253 | if (!*p) | ||
254 | continue; | ||
255 | token = match_token(p, policy_tokens, args); | ||
256 | switch (token) { | ||
257 | case Opt_measure: | ||
258 | audit_log_format(ab, "%s ", "measure"); | ||
259 | entry->action = MEASURE; | ||
260 | break; | ||
261 | case Opt_dont_measure: | ||
262 | audit_log_format(ab, "%s ", "dont_measure"); | ||
263 | entry->action = DONT_MEASURE; | ||
264 | break; | ||
265 | case Opt_func: | ||
266 | audit_log_format(ab, "func=%s ", args[0].from); | ||
267 | if (strcmp(args[0].from, "PATH_CHECK") == 0) | ||
268 | entry->func = PATH_CHECK; | ||
269 | else if (strcmp(args[0].from, "FILE_MMAP") == 0) | ||
270 | entry->func = FILE_MMAP; | ||
271 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) | ||
272 | entry->func = BPRM_CHECK; | ||
273 | else | ||
274 | result = -EINVAL; | ||
275 | if (!result) | ||
276 | entry->flags |= IMA_FUNC; | ||
277 | break; | ||
278 | case Opt_mask: | ||
279 | audit_log_format(ab, "mask=%s ", args[0].from); | ||
280 | if ((strcmp(args[0].from, "MAY_EXEC")) == 0) | ||
281 | entry->mask = MAY_EXEC; | ||
282 | else if (strcmp(args[0].from, "MAY_WRITE") == 0) | ||
283 | entry->mask = MAY_WRITE; | ||
284 | else if (strcmp(args[0].from, "MAY_READ") == 0) | ||
285 | entry->mask = MAY_READ; | ||
286 | else if (strcmp(args[0].from, "MAY_APPEND") == 0) | ||
287 | entry->mask = MAY_APPEND; | ||
288 | else | ||
289 | result = -EINVAL; | ||
290 | if (!result) | ||
291 | entry->flags |= IMA_MASK; | ||
292 | break; | ||
293 | case Opt_fsmagic: | ||
294 | audit_log_format(ab, "fsmagic=%s ", args[0].from); | ||
295 | result = strict_strtoul(args[0].from, 16, | ||
296 | &entry->fsmagic); | ||
297 | if (!result) | ||
298 | entry->flags |= IMA_FSMAGIC; | ||
299 | break; | ||
300 | case Opt_uid: | ||
301 | audit_log_format(ab, "uid=%s ", args[0].from); | ||
302 | result = strict_strtoul(args[0].from, 10, &lnum); | ||
303 | if (!result) { | ||
304 | entry->uid = (uid_t) lnum; | ||
305 | if (entry->uid != lnum) | ||
306 | result = -EINVAL; | ||
307 | else | ||
308 | entry->flags |= IMA_UID; | ||
309 | } | ||
310 | break; | ||
311 | case Opt_obj_user: | ||
312 | audit_log_format(ab, "obj_user=%s ", args[0].from); | ||
313 | result = ima_lsm_rule_init(entry, args[0].from, | ||
314 | LSM_OBJ_USER, | ||
315 | AUDIT_OBJ_USER); | ||
316 | break; | ||
317 | case Opt_obj_role: | ||
318 | audit_log_format(ab, "obj_role=%s ", args[0].from); | ||
319 | result = ima_lsm_rule_init(entry, args[0].from, | ||
320 | LSM_OBJ_ROLE, | ||
321 | AUDIT_OBJ_ROLE); | ||
322 | break; | ||
323 | case Opt_obj_type: | ||
324 | audit_log_format(ab, "obj_type=%s ", args[0].from); | ||
325 | result = ima_lsm_rule_init(entry, args[0].from, | ||
326 | LSM_OBJ_TYPE, | ||
327 | AUDIT_OBJ_TYPE); | ||
328 | break; | ||
329 | case Opt_subj_user: | ||
330 | audit_log_format(ab, "subj_user=%s ", args[0].from); | ||
331 | result = ima_lsm_rule_init(entry, args[0].from, | ||
332 | LSM_SUBJ_USER, | ||
333 | AUDIT_SUBJ_USER); | ||
334 | break; | ||
335 | case Opt_subj_role: | ||
336 | audit_log_format(ab, "subj_role=%s ", args[0].from); | ||
337 | result = ima_lsm_rule_init(entry, args[0].from, | ||
338 | LSM_SUBJ_ROLE, | ||
339 | AUDIT_SUBJ_ROLE); | ||
340 | break; | ||
341 | case Opt_subj_type: | ||
342 | audit_log_format(ab, "subj_type=%s ", args[0].from); | ||
343 | result = ima_lsm_rule_init(entry, args[0].from, | ||
344 | LSM_SUBJ_TYPE, | ||
345 | AUDIT_SUBJ_TYPE); | ||
346 | break; | ||
347 | case Opt_err: | ||
348 | printk(KERN_INFO "%s: unknown token: %s\n", | ||
349 | __FUNCTION__, p); | ||
350 | break; | ||
351 | } | ||
352 | } | ||
353 | if (entry->action == UNKNOWN) | ||
354 | result = -EINVAL; | ||
355 | |||
356 | audit_log_format(ab, "res=%d", result); | ||
357 | audit_log_end(ab); | ||
358 | return result; | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * ima_parse_add_rule - add a rule to measure_policy_rules | ||
363 | * @rule - ima measurement policy rule | ||
364 | * | ||
365 | * Uses a mutex to protect the policy list from multiple concurrent writers. | ||
366 | * Returns 0 on success, an error code on failure. | ||
367 | */ | ||
368 | int ima_parse_add_rule(char *rule) | ||
369 | { | ||
370 | const char *op = "add_rule"; | ||
371 | struct ima_measure_rule_entry *entry; | ||
372 | int result = 0; | ||
373 | int audit_info = 0; | ||
374 | |||
375 | /* Prevent installed policy from changing */ | ||
376 | if (ima_measure != &measure_default_rules) { | ||
377 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
378 | NULL, op, "already exists", | ||
379 | -EACCES, audit_info); | ||
380 | return -EACCES; | ||
381 | } | ||
382 | |||
383 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
384 | if (!entry) { | ||
385 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
386 | NULL, op, "-ENOMEM", -ENOMEM, audit_info); | ||
387 | return -ENOMEM; | ||
388 | } | ||
389 | |||
390 | INIT_LIST_HEAD(&entry->list); | ||
391 | |||
392 | result = ima_parse_rule(rule, entry); | ||
393 | if (!result) { | ||
394 | mutex_lock(&ima_measure_mutex); | ||
395 | list_add_tail(&entry->list, &measure_policy_rules); | ||
396 | mutex_unlock(&ima_measure_mutex); | ||
397 | } else | ||
398 | kfree(entry); | ||
399 | return result; | ||
400 | } | ||
401 | |||
402 | /* ima_delete_rules called to cleanup invalid policy */ | ||
403 | void ima_delete_rules() | ||
404 | { | ||
405 | struct ima_measure_rule_entry *entry, *tmp; | ||
406 | |||
407 | mutex_lock(&ima_measure_mutex); | ||
408 | list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) { | ||
409 | list_del(&entry->list); | ||
410 | kfree(entry); | ||
411 | } | ||
412 | mutex_unlock(&ima_measure_mutex); | ||
413 | } | ||