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