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