d818717954f89ba28b6eedac1b07f2d5f98862ed
[platform/adaptation/renesas_rcar/renesas_kernel.git] / security / tomoyo / domain.c
1 /*
2  * security/tomoyo/domain.c
3  *
4  * Domain transition functions for TOMOYO.
5  *
6  * Copyright (C) 2005-2010  NTT DATA CORPORATION
7  */
8
9 #include "common.h"
10 #include <linux/binfmts.h>
11 #include <linux/slab.h>
12
13 /* Variables definitions.*/
14
15 /* The initial domain. */
16 struct tomoyo_domain_info tomoyo_kernel_domain;
17
18 /**
19  * tomoyo_update_policy - Update an entry for exception policy.
20  *
21  * @new_entry:       Pointer to "struct tomoyo_acl_info".
22  * @size:            Size of @new_entry in bytes.
23  * @param:           Pointer to "struct tomoyo_acl_param".
24  * @check_duplicate: Callback function to find duplicated entry.
25  *
26  * Returns 0 on success, negative value otherwise.
27  *
28  * Caller holds tomoyo_read_lock().
29  */
30 int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
31                          struct tomoyo_acl_param *param,
32                          bool (*check_duplicate) (const struct tomoyo_acl_head
33                                                   *,
34                                                   const struct tomoyo_acl_head
35                                                   *))
36 {
37         int error = param->is_delete ? -ENOENT : -ENOMEM;
38         struct tomoyo_acl_head *entry;
39         struct list_head *list = param->list;
40
41         if (mutex_lock_interruptible(&tomoyo_policy_lock))
42                 return -ENOMEM;
43         list_for_each_entry_rcu(entry, list, list) {
44                 if (!check_duplicate(entry, new_entry))
45                         continue;
46                 entry->is_deleted = param->is_delete;
47                 error = 0;
48                 break;
49         }
50         if (error && !param->is_delete) {
51                 entry = tomoyo_commit_ok(new_entry, size);
52                 if (entry) {
53                         list_add_tail_rcu(&entry->list, list);
54                         error = 0;
55                 }
56         }
57         mutex_unlock(&tomoyo_policy_lock);
58         return error;
59 }
60
61 /**
62  * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry.
63  *
64  * @a: Pointer to "struct tomoyo_acl_info".
65  * @b: Pointer to "struct tomoyo_acl_info".
66  *
67  * Returns true if @a == @b, false otherwise.
68  */
69 static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
70                                         const struct tomoyo_acl_info *b)
71 {
72         return a->type == b->type;
73 }
74
75 /**
76  * tomoyo_update_domain - Update an entry for domain policy.
77  *
78  * @new_entry:       Pointer to "struct tomoyo_acl_info".
79  * @size:            Size of @new_entry in bytes.
80  * @param:           Pointer to "struct tomoyo_acl_param".
81  * @check_duplicate: Callback function to find duplicated entry.
82  * @merge_duplicate: Callback function to merge duplicated entry.
83  *
84  * Returns 0 on success, negative value otherwise.
85  *
86  * Caller holds tomoyo_read_lock().
87  */
88 int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
89                          struct tomoyo_acl_param *param,
90                          bool (*check_duplicate) (const struct tomoyo_acl_info
91                                                   *,
92                                                   const struct tomoyo_acl_info
93                                                   *),
94                          bool (*merge_duplicate) (struct tomoyo_acl_info *,
95                                                   struct tomoyo_acl_info *,
96                                                   const bool))
97 {
98         const bool is_delete = param->is_delete;
99         int error = is_delete ? -ENOENT : -ENOMEM;
100         struct tomoyo_acl_info *entry;
101         struct list_head * const list = param->list;
102
103         if (mutex_lock_interruptible(&tomoyo_policy_lock))
104                 return error;
105         list_for_each_entry_rcu(entry, list, list) {
106                 if (!tomoyo_same_acl_head(entry, new_entry) ||
107                     !check_duplicate(entry, new_entry))
108                         continue;
109                 if (merge_duplicate)
110                         entry->is_deleted = merge_duplicate(entry, new_entry,
111                                                             is_delete);
112                 else
113                         entry->is_deleted = is_delete;
114                 error = 0;
115                 break;
116         }
117         if (error && !is_delete) {
118                 entry = tomoyo_commit_ok(new_entry, size);
119                 if (entry) {
120                         list_add_tail_rcu(&entry->list, list);
121                         error = 0;
122                 }
123         }
124         mutex_unlock(&tomoyo_policy_lock);
125         return error;
126 }
127
128 void tomoyo_check_acl(struct tomoyo_request_info *r,
129                       bool (*check_entry) (struct tomoyo_request_info *,
130                                            const struct tomoyo_acl_info *))
131 {
132         const struct tomoyo_domain_info *domain = r->domain;
133         struct tomoyo_acl_info *ptr;
134
135         list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
136                 if (ptr->is_deleted || ptr->type != r->param_type)
137                         continue;
138                 if (check_entry(r, ptr)) {
139                         r->granted = true;
140                         return;
141                 }
142         }
143         r->granted = false;
144 }
145
146 /* The list for "struct tomoyo_domain_info". */
147 LIST_HEAD(tomoyo_domain_list);
148
149 struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
150 struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
151
152 /**
153  * tomoyo_last_word - Get last component of a domainname.
154  *
155  * @domainname: Domainname to check.
156  *
157  * Returns the last word of @domainname.
158  */
159 static const char *tomoyo_last_word(const char *name)
160 {
161         const char *cp = strrchr(name, ' ');
162         if (cp)
163                 return cp + 1;
164         return name;
165 }
166
167 /**
168  * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
169  *
170  * @a: Pointer to "struct tomoyo_acl_head".
171  * @b: Pointer to "struct tomoyo_acl_head".
172  *
173  * Returns true if @a == @b, false otherwise.
174  */
175 static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
176                                            const struct tomoyo_acl_head *b)
177 {
178         const struct tomoyo_transition_control *p1 = container_of(a,
179                                                                   typeof(*p1),
180                                                                   head);
181         const struct tomoyo_transition_control *p2 = container_of(b,
182                                                                   typeof(*p2),
183                                                                   head);
184         return p1->type == p2->type && p1->is_last_name == p2->is_last_name
185                 && p1->domainname == p2->domainname
186                 && p1->program == p2->program;
187 }
188
189 /**
190  * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
191  *
192  * @param: Pointer to "struct tomoyo_acl_param".
193  * @type:  Type of this entry.
194  *
195  * Returns 0 on success, negative value otherwise.
196  */
197 int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
198                                     const u8 type)
199 {
200         struct tomoyo_transition_control e = { .type = type };
201         int error = param->is_delete ? -ENOENT : -ENOMEM;
202         char *program = param->data;
203         char *domainname = strstr(program, " from ");
204         if (domainname) {
205                 *domainname = '\0';
206                 domainname += 6;
207         } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
208                    type == TOMOYO_TRANSITION_CONTROL_KEEP) {
209                 domainname = program;
210                 program = NULL;
211         }
212         if (program) {
213                 if (!tomoyo_correct_path(program))
214                         return -EINVAL;
215                 e.program = tomoyo_get_name(program);
216                 if (!e.program)
217                         goto out;
218         }
219         if (domainname) {
220                 if (!tomoyo_correct_domain(domainname)) {
221                         if (!tomoyo_correct_path(domainname))
222                                 goto out;
223                         e.is_last_name = true;
224                 }
225                 e.domainname = tomoyo_get_name(domainname);
226                 if (!e.domainname)
227                         goto out;
228         }
229         param->list = &tomoyo_policy_list[TOMOYO_ID_TRANSITION_CONTROL];
230         error = tomoyo_update_policy(&e.head, sizeof(e), param,
231                                      tomoyo_same_transition_control);
232 out:
233         tomoyo_put_name(e.domainname);
234         tomoyo_put_name(e.program);
235         return error;
236 }
237
238 /**
239  * tomoyo_transition_type - Get domain transition type.
240  *
241  * @domainname: The name of domain.
242  * @program:    The name of program.
243  *
244  * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program
245  * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
246  * @program suppresses domain transition, others otherwise.
247  *
248  * Caller holds tomoyo_read_lock().
249  */
250 static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname,
251                                  const struct tomoyo_path_info *program)
252 {
253         const struct tomoyo_transition_control *ptr;
254         const char *last_name = tomoyo_last_word(domainname->name);
255         u8 type;
256         for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) {
257  next:
258                 list_for_each_entry_rcu(ptr, &tomoyo_policy_list
259                                         [TOMOYO_ID_TRANSITION_CONTROL],
260                                         head.list) {
261                         if (ptr->head.is_deleted || ptr->type != type)
262                                 continue;
263                         if (ptr->domainname) {
264                                 if (!ptr->is_last_name) {
265                                         if (ptr->domainname != domainname)
266                                                 continue;
267                                 } else {
268                                         /*
269                                          * Use direct strcmp() since this is
270                                          * unlikely used.
271                                          */
272                                         if (strcmp(ptr->domainname->name,
273                                                    last_name))
274                                                 continue;
275                                 }
276                         }
277                         if (ptr->program &&
278                             tomoyo_pathcmp(ptr->program, program))
279                                 continue;
280                         if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) {
281                                 /*
282                                  * Do not check for initialize_domain if
283                                  * no_initialize_domain matched.
284                                  */
285                                 type = TOMOYO_TRANSITION_CONTROL_NO_KEEP;
286                                 goto next;
287                         }
288                         goto done;
289                 }
290         }
291  done:
292         return type;
293 }
294
295 /**
296  * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
297  *
298  * @a: Pointer to "struct tomoyo_acl_head".
299  * @b: Pointer to "struct tomoyo_acl_head".
300  *
301  * Returns true if @a == @b, false otherwise.
302  */
303 static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
304                                    const struct tomoyo_acl_head *b)
305 {
306         const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1),
307                                                           head);
308         const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
309                                                           head);
310         return p1->original_name == p2->original_name &&
311                 p1->aggregated_name == p2->aggregated_name;
312 }
313
314 /**
315  * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
316  *
317  * @param: Pointer to "struct tomoyo_acl_param".
318  *
319  * Returns 0 on success, negative value otherwise.
320  *
321  * Caller holds tomoyo_read_lock().
322  */
323 int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
324 {
325         struct tomoyo_aggregator e = { };
326         int error = param->is_delete ? -ENOENT : -ENOMEM;
327         const char *original_name = tomoyo_read_token(param);
328         const char *aggregated_name = tomoyo_read_token(param);
329         if (!tomoyo_correct_word(original_name) ||
330             !tomoyo_correct_path(aggregated_name))
331                 return -EINVAL;
332         e.original_name = tomoyo_get_name(original_name);
333         e.aggregated_name = tomoyo_get_name(aggregated_name);
334         if (!e.original_name || !e.aggregated_name ||
335             e.aggregated_name->is_patterned) /* No patterns allowed. */
336                 goto out;
337         param->list = &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR];
338         error = tomoyo_update_policy(&e.head, sizeof(e), param,
339                                      tomoyo_same_aggregator);
340 out:
341         tomoyo_put_name(e.original_name);
342         tomoyo_put_name(e.aggregated_name);
343         return error;
344 }
345
346 /**
347  * tomoyo_assign_domain - Create a domain.
348  *
349  * @domainname: The name of domain.
350  * @profile:    Profile number to assign if the domain was newly created.
351  *
352  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
353  *
354  * Caller holds tomoyo_read_lock().
355  */
356 struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
357                                                 const u8 profile)
358 {
359         struct tomoyo_domain_info *entry;
360         struct tomoyo_domain_info *domain = NULL;
361         const struct tomoyo_path_info *saved_domainname;
362         bool found = false;
363
364         if (!tomoyo_correct_domain(domainname))
365                 return NULL;
366         saved_domainname = tomoyo_get_name(domainname);
367         if (!saved_domainname)
368                 return NULL;
369         entry = kzalloc(sizeof(*entry), GFP_NOFS);
370         if (mutex_lock_interruptible(&tomoyo_policy_lock))
371                 goto out;
372         list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
373                 if (domain->is_deleted ||
374                     tomoyo_pathcmp(saved_domainname, domain->domainname))
375                         continue;
376                 found = true;
377                 break;
378         }
379         if (!found && tomoyo_memory_ok(entry)) {
380                 INIT_LIST_HEAD(&entry->acl_info_list);
381                 entry->domainname = saved_domainname;
382                 saved_domainname = NULL;
383                 entry->profile = profile;
384                 list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
385                 domain = entry;
386                 entry = NULL;
387                 found = true;
388         }
389         mutex_unlock(&tomoyo_policy_lock);
390  out:
391         tomoyo_put_name(saved_domainname);
392         kfree(entry);
393         return found ? domain : NULL;
394 }
395
396 /**
397  * tomoyo_find_next_domain - Find a domain.
398  *
399  * @bprm: Pointer to "struct linux_binprm".
400  *
401  * Returns 0 on success, negative value otherwise.
402  *
403  * Caller holds tomoyo_read_lock().
404  */
405 int tomoyo_find_next_domain(struct linux_binprm *bprm)
406 {
407         struct tomoyo_request_info r;
408         char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
409         struct tomoyo_domain_info *old_domain = tomoyo_domain();
410         struct tomoyo_domain_info *domain = NULL;
411         const char *original_name = bprm->filename;
412         u8 mode;
413         bool is_enforce;
414         int retval = -ENOMEM;
415         bool need_kfree = false;
416         struct tomoyo_path_info rn = { }; /* real name */
417
418         mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
419         is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
420         if (!tmp)
421                 goto out;
422
423  retry:
424         if (need_kfree) {
425                 kfree(rn.name);
426                 need_kfree = false;
427         }
428         /* Get symlink's pathname of program. */
429         retval = -ENOENT;
430         rn.name = tomoyo_realpath_nofollow(original_name);
431         if (!rn.name)
432                 goto out;
433         tomoyo_fill_path_info(&rn);
434         need_kfree = true;
435
436         /* Check 'aggregator' directive. */
437         {
438                 struct tomoyo_aggregator *ptr;
439                 list_for_each_entry_rcu(ptr, &tomoyo_policy_list
440                                         [TOMOYO_ID_AGGREGATOR], head.list) {
441                         if (ptr->head.is_deleted ||
442                             !tomoyo_path_matches_pattern(&rn,
443                                                          ptr->original_name))
444                                 continue;
445                         kfree(rn.name);
446                         need_kfree = false;
447                         /* This is OK because it is read only. */
448                         rn = *ptr->aggregated_name;
449                         break;
450                 }
451         }
452
453         /* Check execute permission. */
454         retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn);
455         if (retval == TOMOYO_RETRY_REQUEST)
456                 goto retry;
457         if (retval < 0)
458                 goto out;
459         /*
460          * To be able to specify domainnames with wildcards, use the
461          * pathname specified in the policy (which may contain
462          * wildcard) rather than the pathname passed to execve()
463          * (which never contains wildcard).
464          */
465         if (r.param.path.matched_path) {
466                 if (need_kfree)
467                         kfree(rn.name);
468                 need_kfree = false;
469                 /* This is OK because it is read only. */
470                 rn = *r.param.path.matched_path;
471         }
472
473         /* Calculate domain to transit to. */
474         switch (tomoyo_transition_type(old_domain->domainname, &rn)) {
475         case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
476                 /* Transit to the child of tomoyo_kernel_domain domain. */
477                 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " "
478                          "%s", rn.name);
479                 break;
480         case TOMOYO_TRANSITION_CONTROL_KEEP:
481                 /* Keep current domain. */
482                 domain = old_domain;
483                 break;
484         default:
485                 if (old_domain == &tomoyo_kernel_domain &&
486                     !tomoyo_policy_loaded) {
487                         /*
488                          * Needn't to transit from kernel domain before
489                          * starting /sbin/init. But transit from kernel domain
490                          * if executing initializers because they might start
491                          * before /sbin/init.
492                          */
493                         domain = old_domain;
494                 } else {
495                         /* Normal domain transition. */
496                         snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
497                                  old_domain->domainname->name, rn.name);
498                 }
499                 break;
500         }
501         if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
502                 goto done;
503         domain = tomoyo_find_domain(tmp);
504         if (!domain)
505                 domain = tomoyo_assign_domain(tmp, old_domain->profile);
506  done:
507         if (domain)
508                 goto out;
509         printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
510         if (is_enforce)
511                 retval = -EPERM;
512         else
513                 old_domain->transition_failed = true;
514  out:
515         if (!domain)
516                 domain = old_domain;
517         /* Update reference count on "struct tomoyo_domain_info". */
518         atomic_inc(&domain->users);
519         bprm->cred->security = domain;
520         if (need_kfree)
521                 kfree(rn.name);
522         kfree(tmp);
523         return retval;
524 }