]> Git Repo - linux.git/blob - security/integrity/ima/ima_policy.c
IMA: fix ima_delete_rules() definition
[linux.git] / security / integrity / ima / ima_policy.c
1 /*
2  * Copyright (C) 2008 IBM Corporation
3  * Author: Mimi Zohar <[email protected]>
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
10  *      - initialize default measure policy rules
11  *
12  */
13 #include <linux/module.h>
14 #include <linux/list.h>
15 #include <linux/audit.h>
16 #include <linux/security.h>
17 #include <linux/magic.h>
18 #include <linux/parser.h>
19
20 #include "ima.h"
21
22 /* flags definitions */
23 #define IMA_FUNC        0x0001
24 #define IMA_MASK        0x0002
25 #define IMA_FSMAGIC     0x0004
26 #define IMA_UID         0x0008
27
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 };
34
35 struct ima_measure_rule_entry {
36         struct list_head list;
37         enum ima_action action;
38         unsigned int flags;
39         enum ima_hooks func;
40         int mask;
41         unsigned long fsmagic;
42         uid_t uid;
43         struct {
44                 void *rule;     /* LSM file metadata specific */
45                 int type;       /* audit type */
46         } lsm[MAX_LSM_RULES];
47 };
48
49 /* Without LSM specific knowledge, the default policy can only be
50  * written in terms of .action, .func, .mask, .fsmagic, and .uid
51  */
52 static struct ima_measure_rule_entry default_rules[] = {
53         {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,
54          .flags = IMA_FSMAGIC},
55         {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
56         {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
57         {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
58         {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,
59          .flags = IMA_FSMAGIC},
60         {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC},
61         {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
62          .flags = IMA_FUNC | IMA_MASK},
63         {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC,
64          .flags = IMA_FUNC | IMA_MASK},
65         {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0,
66          .flags = IMA_FUNC | IMA_MASK | IMA_UID}
67 };
68
69 static LIST_HEAD(measure_default_rules);
70 static LIST_HEAD(measure_policy_rules);
71 static struct list_head *ima_measure;
72
73 static DEFINE_MUTEX(ima_measure_mutex);
74
75 /**
76  * ima_match_rules - determine whether an inode matches the measure rule.
77  * @rule: a pointer to a rule
78  * @inode: a pointer to an inode
79  * @func: LIM hook identifier
80  * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
81  *
82  * Returns true on rule match, false on failure.
83  */
84 static bool ima_match_rules(struct ima_measure_rule_entry *rule,
85                             struct inode *inode, enum ima_hooks func, int mask)
86 {
87         struct task_struct *tsk = current;
88         int i;
89
90         if ((rule->flags & IMA_FUNC) && rule->func != func)
91                 return false;
92         if ((rule->flags & IMA_MASK) && rule->mask != mask)
93                 return false;
94         if ((rule->flags & IMA_FSMAGIC)
95             && rule->fsmagic != inode->i_sb->s_magic)
96                 return false;
97         if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid)
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         }
132         return true;
133 }
134
135 /**
136  * ima_match_policy - decision based on LSM and other conditions
137  * @inode: pointer to an inode for which the policy decision is being made
138  * @func: IMA hook identifier
139  * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
140  *
141  * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
142  * conditions.
143  *
144  * (There is no need for locking when walking the policy list,
145  * as elements in the list are never deleted, nor does the list
146  * change.)
147  */
148 int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask)
149 {
150         struct ima_measure_rule_entry *entry;
151
152         list_for_each_entry(entry, ima_measure, list) {
153                 bool rc;
154
155                 rc = ima_match_rules(entry, inode, func, mask);
156                 if (rc)
157                         return entry->action;
158         }
159         return 0;
160 }
161
162 /**
163  * ima_init_policy - initialize the default measure rules.
164  *
165  * ima_measure points to either the measure_default_rules or the
166  * the new measure_policy_rules.
167  */
168 void ima_init_policy(void)
169 {
170         int i;
171
172         for (i = 0; i < ARRAY_SIZE(default_rules); i++)
173                 list_add_tail(&default_rules[i].list, &measure_default_rules);
174         ima_measure = &measure_default_rules;
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(void)
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 }
This page took 0.05501 seconds and 4 git commands to generate.