da16dfeed72800f26bd9bc12b8f68610f51706a1
[firefly-linux-kernel-4.4.55.git] / security / tomoyo / domain.c
1 /*
2  * security/tomoyo/domain.c
3  *
4  * Copyright (C) 2005-2011  NTT DATA CORPORATION
5  */
6
7 #include "common.h"
8 #include <linux/binfmts.h>
9 #include <linux/slab.h>
10
11 /* Variables definitions.*/
12
13 /* The initial domain. */
14 struct tomoyo_domain_info tomoyo_kernel_domain;
15
16 /**
17  * tomoyo_update_policy - Update an entry for exception policy.
18  *
19  * @new_entry:       Pointer to "struct tomoyo_acl_info".
20  * @size:            Size of @new_entry in bytes.
21  * @param:           Pointer to "struct tomoyo_acl_param".
22  * @check_duplicate: Callback function to find duplicated entry.
23  *
24  * Returns 0 on success, negative value otherwise.
25  *
26  * Caller holds tomoyo_read_lock().
27  */
28 int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
29                          struct tomoyo_acl_param *param,
30                          bool (*check_duplicate) (const struct tomoyo_acl_head
31                                                   *,
32                                                   const struct tomoyo_acl_head
33                                                   *))
34 {
35         int error = param->is_delete ? -ENOENT : -ENOMEM;
36         struct tomoyo_acl_head *entry;
37         struct list_head *list = param->list;
38
39         if (mutex_lock_interruptible(&tomoyo_policy_lock))
40                 return -ENOMEM;
41         list_for_each_entry_rcu(entry, list, list) {
42                 if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
43                         continue;
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 && a->cond == b->cond;
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 (param->data[0]) {
104                 new_entry->cond = tomoyo_get_condition(param);
105                 if (!new_entry->cond)
106                         return -EINVAL;
107                 /*
108                  * Domain transition preference is allowed for only
109                  * "file execute" entries.
110                  */
111                 if (new_entry->cond->transit &&
112                     !(new_entry->type == TOMOYO_TYPE_PATH_ACL &&
113                       container_of(new_entry, struct tomoyo_path_acl, head)
114                       ->perm == 1 << TOMOYO_TYPE_EXECUTE))
115                         goto out;
116         }
117         if (mutex_lock_interruptible(&tomoyo_policy_lock))
118                 goto out;
119         list_for_each_entry_rcu(entry, list, list) {
120                 if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
121                         continue;
122                 if (!tomoyo_same_acl_head(entry, new_entry) ||
123                     !check_duplicate(entry, new_entry))
124                         continue;
125                 if (merge_duplicate)
126                         entry->is_deleted = merge_duplicate(entry, new_entry,
127                                                             is_delete);
128                 else
129                         entry->is_deleted = is_delete;
130                 error = 0;
131                 break;
132         }
133         if (error && !is_delete) {
134                 entry = tomoyo_commit_ok(new_entry, size);
135                 if (entry) {
136                         list_add_tail_rcu(&entry->list, list);
137                         error = 0;
138                 }
139         }
140         mutex_unlock(&tomoyo_policy_lock);
141 out:
142         tomoyo_put_condition(new_entry->cond);
143         return error;
144 }
145
146 /**
147  * tomoyo_check_acl - Do permission check.
148  *
149  * @r:           Pointer to "struct tomoyo_request_info".
150  * @check_entry: Callback function to check type specific parameters.
151  *
152  * Returns 0 on success, negative value otherwise.
153  *
154  * Caller holds tomoyo_read_lock().
155  */
156 void tomoyo_check_acl(struct tomoyo_request_info *r,
157                       bool (*check_entry) (struct tomoyo_request_info *,
158                                            const struct tomoyo_acl_info *))
159 {
160         const struct tomoyo_domain_info *domain = r->domain;
161         struct tomoyo_acl_info *ptr;
162         bool retried = false;
163         const struct list_head *list = &domain->acl_info_list;
164
165 retry:
166         list_for_each_entry_rcu(ptr, list, list) {
167                 if (ptr->is_deleted || ptr->type != r->param_type)
168                         continue;
169                 if (!check_entry(r, ptr))
170                         continue;
171                 if (!tomoyo_condition(r, ptr->cond))
172                         continue;
173                 r->matched_acl = ptr;
174                 r->granted = true;
175                 return;
176         }
177         if (!retried) {
178                 retried = true;
179                 list = &domain->ns->acl_group[domain->group];
180                 goto retry;
181         }
182         r->granted = false;
183 }
184
185 /* The list for "struct tomoyo_domain_info". */
186 LIST_HEAD(tomoyo_domain_list);
187
188 /**
189  * tomoyo_last_word - Get last component of a domainname.
190  *
191  * @name: Domainname to check.
192  *
193  * Returns the last word of @domainname.
194  */
195 static const char *tomoyo_last_word(const char *name)
196 {
197         const char *cp = strrchr(name, ' ');
198         if (cp)
199                 return cp + 1;
200         return name;
201 }
202
203 /**
204  * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
205  *
206  * @a: Pointer to "struct tomoyo_acl_head".
207  * @b: Pointer to "struct tomoyo_acl_head".
208  *
209  * Returns true if @a == @b, false otherwise.
210  */
211 static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
212                                            const struct tomoyo_acl_head *b)
213 {
214         const struct tomoyo_transition_control *p1 = container_of(a,
215                                                                   typeof(*p1),
216                                                                   head);
217         const struct tomoyo_transition_control *p2 = container_of(b,
218                                                                   typeof(*p2),
219                                                                   head);
220         return p1->type == p2->type && p1->is_last_name == p2->is_last_name
221                 && p1->domainname == p2->domainname
222                 && p1->program == p2->program;
223 }
224
225 /**
226  * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
227  *
228  * @param: Pointer to "struct tomoyo_acl_param".
229  * @type:  Type of this entry.
230  *
231  * Returns 0 on success, negative value otherwise.
232  */
233 int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
234                                     const u8 type)
235 {
236         struct tomoyo_transition_control e = { .type = type };
237         int error = param->is_delete ? -ENOENT : -ENOMEM;
238         char *program = param->data;
239         char *domainname = strstr(program, " from ");
240         if (domainname) {
241                 *domainname = '\0';
242                 domainname += 6;
243         } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
244                    type == TOMOYO_TRANSITION_CONTROL_KEEP) {
245                 domainname = program;
246                 program = NULL;
247         }
248         if (program && strcmp(program, "any")) {
249                 if (!tomoyo_correct_path(program))
250                         return -EINVAL;
251                 e.program = tomoyo_get_name(program);
252                 if (!e.program)
253                         goto out;
254         }
255         if (domainname && strcmp(domainname, "any")) {
256                 if (!tomoyo_correct_domain(domainname)) {
257                         if (!tomoyo_correct_path(domainname))
258                                 goto out;
259                         e.is_last_name = true;
260                 }
261                 e.domainname = tomoyo_get_name(domainname);
262                 if (!e.domainname)
263                         goto out;
264         }
265         param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
266         error = tomoyo_update_policy(&e.head, sizeof(e), param,
267                                      tomoyo_same_transition_control);
268 out:
269         tomoyo_put_name(e.domainname);
270         tomoyo_put_name(e.program);
271         return error;
272 }
273
274 /**
275  * tomoyo_scan_transition - Try to find specific domain transition type.
276  *
277  * @list:       Pointer to "struct list_head".
278  * @domainname: The name of current domain.
279  * @program:    The name of requested program.
280  * @last_name:  The last component of @domainname.
281  * @type:       One of values in "enum tomoyo_transition_type".
282  *
283  * Returns true if found one, false otherwise.
284  *
285  * Caller holds tomoyo_read_lock().
286  */
287 static inline bool tomoyo_scan_transition
288 (const struct list_head *list, const struct tomoyo_path_info *domainname,
289  const struct tomoyo_path_info *program, const char *last_name,
290  const enum tomoyo_transition_type type)
291 {
292         const struct tomoyo_transition_control *ptr;
293         list_for_each_entry_rcu(ptr, list, head.list) {
294                 if (ptr->head.is_deleted || ptr->type != type)
295                         continue;
296                 if (ptr->domainname) {
297                         if (!ptr->is_last_name) {
298                                 if (ptr->domainname != domainname)
299                                         continue;
300                         } else {
301                                 /*
302                                  * Use direct strcmp() since this is
303                                  * unlikely used.
304                                  */
305                                 if (strcmp(ptr->domainname->name, last_name))
306                                         continue;
307                         }
308                 }
309                 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
310                         continue;
311                 return true;
312         }
313         return false;
314 }
315
316 /**
317  * tomoyo_transition_type - Get domain transition type.
318  *
319  * @ns:         Pointer to "struct tomoyo_policy_namespace".
320  * @domainname: The name of current domain.
321  * @program:    The name of requested program.
322  *
323  * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes
324  * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if
325  * executing @program reinitializes domain transition within that namespace,
326  * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
327  * others otherwise.
328  *
329  * Caller holds tomoyo_read_lock().
330  */
331 static enum tomoyo_transition_type tomoyo_transition_type
332 (const struct tomoyo_policy_namespace *ns,
333  const struct tomoyo_path_info *domainname,
334  const struct tomoyo_path_info *program)
335 {
336         const char *last_name = tomoyo_last_word(domainname->name);
337         enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
338         while (type < TOMOYO_MAX_TRANSITION_TYPE) {
339                 const struct list_head * const list =
340                         &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
341                 if (!tomoyo_scan_transition(list, domainname, program,
342                                             last_name, type)) {
343                         type++;
344                         continue;
345                 }
346                 if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET &&
347                     type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE)
348                         break;
349                 /*
350                  * Do not check for reset_domain if no_reset_domain matched.
351                  * Do not check for initialize_domain if no_initialize_domain
352                  * matched.
353                  */
354                 type++;
355                 type++;
356         }
357         return type;
358 }
359
360 /**
361  * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
362  *
363  * @a: Pointer to "struct tomoyo_acl_head".
364  * @b: Pointer to "struct tomoyo_acl_head".
365  *
366  * Returns true if @a == @b, false otherwise.
367  */
368 static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
369                                    const struct tomoyo_acl_head *b)
370 {
371         const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1),
372                                                           head);
373         const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
374                                                           head);
375         return p1->original_name == p2->original_name &&
376                 p1->aggregated_name == p2->aggregated_name;
377 }
378
379 /**
380  * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
381  *
382  * @param: Pointer to "struct tomoyo_acl_param".
383  *
384  * Returns 0 on success, negative value otherwise.
385  *
386  * Caller holds tomoyo_read_lock().
387  */
388 int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
389 {
390         struct tomoyo_aggregator e = { };
391         int error = param->is_delete ? -ENOENT : -ENOMEM;
392         const char *original_name = tomoyo_read_token(param);
393         const char *aggregated_name = tomoyo_read_token(param);
394         if (!tomoyo_correct_word(original_name) ||
395             !tomoyo_correct_path(aggregated_name))
396                 return -EINVAL;
397         e.original_name = tomoyo_get_name(original_name);
398         e.aggregated_name = tomoyo_get_name(aggregated_name);
399         if (!e.original_name || !e.aggregated_name ||
400             e.aggregated_name->is_patterned) /* No patterns allowed. */
401                 goto out;
402         param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
403         error = tomoyo_update_policy(&e.head, sizeof(e), param,
404                                      tomoyo_same_aggregator);
405 out:
406         tomoyo_put_name(e.original_name);
407         tomoyo_put_name(e.aggregated_name);
408         return error;
409 }
410
411 /**
412  * tomoyo_find_namespace - Find specified namespace.
413  *
414  * @name: Name of namespace to find.
415  * @len:  Length of @name.
416  *
417  * Returns pointer to "struct tomoyo_policy_namespace" if found,
418  * NULL otherwise.
419  *
420  * Caller holds tomoyo_read_lock().
421  */
422 static struct tomoyo_policy_namespace *tomoyo_find_namespace
423 (const char *name, const unsigned int len)
424 {
425         struct tomoyo_policy_namespace *ns;
426         list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
427                 if (strncmp(name, ns->name, len) ||
428                     (name[len] && name[len] != ' '))
429                         continue;
430                 return ns;
431         }
432         return NULL;
433 }
434
435 /**
436  * tomoyo_assign_namespace - Create a new namespace.
437  *
438  * @domainname: Name of namespace to create.
439  *
440  * Returns pointer to "struct tomoyo_policy_namespace" on success,
441  * NULL otherwise.
442  *
443  * Caller holds tomoyo_read_lock().
444  */
445 struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
446 {
447         struct tomoyo_policy_namespace *ptr;
448         struct tomoyo_policy_namespace *entry;
449         const char *cp = domainname;
450         unsigned int len = 0;
451         while (*cp && *cp++ != ' ')
452                 len++;
453         ptr = tomoyo_find_namespace(domainname, len);
454         if (ptr)
455                 return ptr;
456         if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname))
457                 return NULL;
458         entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
459         if (!entry)
460                 return NULL;
461         if (mutex_lock_interruptible(&tomoyo_policy_lock))
462                 goto out;
463         ptr = tomoyo_find_namespace(domainname, len);
464         if (!ptr && tomoyo_memory_ok(entry)) {
465                 char *name = (char *) (entry + 1);
466                 ptr = entry;
467                 memmove(name, domainname, len);
468                 name[len] = '\0';
469                 entry->name = name;
470                 tomoyo_init_policy_namespace(entry);
471                 entry = NULL;
472         }
473         mutex_unlock(&tomoyo_policy_lock);
474 out:
475         kfree(entry);
476         return ptr;
477 }
478
479 /**
480  * tomoyo_namespace_jump - Check for namespace jump.
481  *
482  * @domainname: Name of domain.
483  *
484  * Returns true if namespace differs, false otherwise.
485  */
486 static bool tomoyo_namespace_jump(const char *domainname)
487 {
488         const char *namespace = tomoyo_current_namespace()->name;
489         const int len = strlen(namespace);
490         return strncmp(domainname, namespace, len) ||
491                 (domainname[len] && domainname[len] != ' ');
492 }
493
494 /**
495  * tomoyo_assign_domain - Create a domain or a namespace.
496  *
497  * @domainname: The name of domain.
498  * @transit:    True if transit to domain found or created.
499  *
500  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
501  *
502  * Caller holds tomoyo_read_lock().
503  */
504 struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
505                                                 const bool transit)
506 {
507         struct tomoyo_domain_info e = { };
508         struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
509         bool created = false;
510         if (entry) {
511                 if (transit) {
512                         /*
513                          * Since namespace is created at runtime, profiles may
514                          * not be created by the moment the process transits to
515                          * that domain. Do not perform domain transition if
516                          * profile for that domain is not yet created.
517                          */
518                         if (!entry->ns->profile_ptr[entry->profile])
519                                 return NULL;
520                 }
521                 return entry;
522         }
523         /* Requested domain does not exist. */
524         /* Don't create requested domain if domainname is invalid. */
525         if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
526             !tomoyo_correct_domain(domainname))
527                 return NULL;
528         /*
529          * Since definition of profiles and acl_groups may differ across
530          * namespaces, do not inherit "use_profile" and "use_group" settings
531          * by automatically creating requested domain upon domain transition.
532          */
533         if (transit && tomoyo_namespace_jump(domainname))
534                 return NULL;
535         e.ns = tomoyo_assign_namespace(domainname);
536         if (!e.ns)
537                 return NULL;
538         /*
539          * "use_profile" and "use_group" settings for automatically created
540          * domains are inherited from current domain. These are 0 for manually
541          * created domains.
542          */
543         if (transit) {
544                 const struct tomoyo_domain_info *domain = tomoyo_domain();
545                 e.profile = domain->profile;
546                 e.group = domain->group;
547         }
548         e.domainname = tomoyo_get_name(domainname);
549         if (!e.domainname)
550                 return NULL;
551         if (mutex_lock_interruptible(&tomoyo_policy_lock))
552                 goto out;
553         entry = tomoyo_find_domain(domainname);
554         if (!entry) {
555                 entry = tomoyo_commit_ok(&e, sizeof(e));
556                 if (entry) {
557                         INIT_LIST_HEAD(&entry->acl_info_list);
558                         list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
559                         created = true;
560                 }
561         }
562         mutex_unlock(&tomoyo_policy_lock);
563 out:
564         tomoyo_put_name(e.domainname);
565         if (entry && transit) {
566                 if (created) {
567                         struct tomoyo_request_info r;
568                         tomoyo_init_request_info(&r, entry,
569                                                  TOMOYO_MAC_FILE_EXECUTE);
570                         r.granted = false;
571                         tomoyo_write_log(&r, "use_profile %u\n",
572                                          entry->profile);
573                         tomoyo_write_log(&r, "use_group %u\n", entry->group);
574                         tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
575                 }
576         }
577         return entry;
578 }
579
580 /**
581  * tomoyo_environ - Check permission for environment variable names.
582  *
583  * @ee: Pointer to "struct tomoyo_execve".
584  *
585  * Returns 0 on success, negative value otherwise.
586  */
587 static int tomoyo_environ(struct tomoyo_execve *ee)
588 {
589         struct tomoyo_request_info *r = &ee->r;
590         struct linux_binprm *bprm = ee->bprm;
591         /* env_page.data is allocated by tomoyo_dump_page(). */
592         struct tomoyo_page_dump env_page = { };
593         char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
594         int arg_len = 0;
595         unsigned long pos = bprm->p;
596         int offset = pos % PAGE_SIZE;
597         int argv_count = bprm->argc;
598         int envp_count = bprm->envc;
599         int error = -ENOMEM;
600
601         ee->r.type = TOMOYO_MAC_ENVIRON;
602         ee->r.profile = r->domain->profile;
603         ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile,
604                                      TOMOYO_MAC_ENVIRON);
605         if (!r->mode || !envp_count)
606                 return 0;
607         arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
608         if (!arg_ptr)
609                 goto out;
610         while (error == -ENOMEM) {
611                 if (!tomoyo_dump_page(bprm, pos, &env_page))
612                         goto out;
613                 pos += PAGE_SIZE - offset;
614                 /* Read. */
615                 while (argv_count && offset < PAGE_SIZE) {
616                         if (!env_page.data[offset++])
617                                 argv_count--;
618                 }
619                 if (argv_count) {
620                         offset = 0;
621                         continue;
622                 }
623                 while (offset < PAGE_SIZE) {
624                         const unsigned char c = env_page.data[offset++];
625
626                         if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
627                                 if (c == '=') {
628                                         arg_ptr[arg_len++] = '\0';
629                                 } else if (c == '\\') {
630                                         arg_ptr[arg_len++] = '\\';
631                                         arg_ptr[arg_len++] = '\\';
632                                 } else if (c > ' ' && c < 127) {
633                                         arg_ptr[arg_len++] = c;
634                                 } else {
635                                         arg_ptr[arg_len++] = '\\';
636                                         arg_ptr[arg_len++] = (c >> 6) + '0';
637                                         arg_ptr[arg_len++]
638                                                 = ((c >> 3) & 7) + '0';
639                                         arg_ptr[arg_len++] = (c & 7) + '0';
640                                 }
641                         } else {
642                                 arg_ptr[arg_len] = '\0';
643                         }
644                         if (c)
645                                 continue;
646                         if (tomoyo_env_perm(r, arg_ptr)) {
647                                 error = -EPERM;
648                                 break;
649                         }
650                         if (!--envp_count) {
651                                 error = 0;
652                                 break;
653                         }
654                         arg_len = 0;
655                 }
656                 offset = 0;
657         }
658 out:
659         if (r->mode != TOMOYO_CONFIG_ENFORCING)
660                 error = 0;
661         kfree(env_page.data);
662         kfree(arg_ptr);
663         return error;
664 }
665
666 /**
667  * tomoyo_find_next_domain - Find a domain.
668  *
669  * @bprm: Pointer to "struct linux_binprm".
670  *
671  * Returns 0 on success, negative value otherwise.
672  *
673  * Caller holds tomoyo_read_lock().
674  */
675 int tomoyo_find_next_domain(struct linux_binprm *bprm)
676 {
677         struct tomoyo_domain_info *old_domain = tomoyo_domain();
678         struct tomoyo_domain_info *domain = NULL;
679         const char *original_name = bprm->filename;
680         int retval = -ENOMEM;
681         bool reject_on_transition_failure = false;
682         const struct tomoyo_path_info *candidate;
683         struct tomoyo_path_info exename;
684         struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
685
686         if (!ee)
687                 return -ENOMEM;
688         ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
689         if (!ee->tmp) {
690                 kfree(ee);
691                 return -ENOMEM;
692         }
693         /* ee->dump->data is allocated by tomoyo_dump_page(). */
694         tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE);
695         ee->r.ee = ee;
696         ee->bprm = bprm;
697         ee->r.obj = &ee->obj;
698         ee->obj.path1 = bprm->file->f_path;
699         /* Get symlink's pathname of program. */
700         retval = -ENOENT;
701         exename.name = tomoyo_realpath_nofollow(original_name);
702         if (!exename.name)
703                 goto out;
704         tomoyo_fill_path_info(&exename);
705 retry:
706         /* Check 'aggregator' directive. */
707         {
708                 struct tomoyo_aggregator *ptr;
709                 struct list_head *list =
710                         &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
711                 /* Check 'aggregator' directive. */
712                 candidate = &exename;
713                 list_for_each_entry_rcu(ptr, list, head.list) {
714                         if (ptr->head.is_deleted ||
715                             !tomoyo_path_matches_pattern(&exename,
716                                                          ptr->original_name))
717                                 continue;
718                         candidate = ptr->aggregated_name;
719                         break;
720                 }
721         }
722
723         /* Check execute permission. */
724         retval = tomoyo_execute_permission(&ee->r, candidate);
725         if (retval == TOMOYO_RETRY_REQUEST)
726                 goto retry;
727         if (retval < 0)
728                 goto out;
729         /*
730          * To be able to specify domainnames with wildcards, use the
731          * pathname specified in the policy (which may contain
732          * wildcard) rather than the pathname passed to execve()
733          * (which never contains wildcard).
734          */
735         if (ee->r.param.path.matched_path)
736                 candidate = ee->r.param.path.matched_path;
737
738         /*
739          * Check for domain transition preference if "file execute" matched.
740          * If preference is given, make do_execve() fail if domain transition
741          * has failed, for domain transition preference should be used with
742          * destination domain defined.
743          */
744         if (ee->transition) {
745                 const char *domainname = ee->transition->name;
746                 reject_on_transition_failure = true;
747                 if (!strcmp(domainname, "keep"))
748                         goto force_keep_domain;
749                 if (!strcmp(domainname, "child"))
750                         goto force_child_domain;
751                 if (!strcmp(domainname, "reset"))
752                         goto force_reset_domain;
753                 if (!strcmp(domainname, "initialize"))
754                         goto force_initialize_domain;
755                 if (!strcmp(domainname, "parent")) {
756                         char *cp;
757                         strncpy(ee->tmp, old_domain->domainname->name,
758                                 TOMOYO_EXEC_TMPSIZE - 1);
759                         cp = strrchr(ee->tmp, ' ');
760                         if (cp)
761                                 *cp = '\0';
762                 } else if (*domainname == '<')
763                         strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
764                 else
765                         snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
766                                  old_domain->domainname->name, domainname);
767                 goto force_jump_domain;
768         }
769         /*
770          * No domain transition preference specified.
771          * Calculate domain to transit to.
772          */
773         switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
774                                        candidate)) {
775         case TOMOYO_TRANSITION_CONTROL_RESET:
776 force_reset_domain:
777                 /* Transit to the root of specified namespace. */
778                 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
779                          candidate->name);
780                 /*
781                  * Make do_execve() fail if domain transition across namespaces
782                  * has failed.
783                  */
784                 reject_on_transition_failure = true;
785                 break;
786         case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
787 force_initialize_domain:
788                 /* Transit to the child of current namespace's root. */
789                 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
790                          old_domain->ns->name, candidate->name);
791                 break;
792         case TOMOYO_TRANSITION_CONTROL_KEEP:
793 force_keep_domain:
794                 /* Keep current domain. */
795                 domain = old_domain;
796                 break;
797         default:
798                 if (old_domain == &tomoyo_kernel_domain &&
799                     !tomoyo_policy_loaded) {
800                         /*
801                          * Needn't to transit from kernel domain before
802                          * starting /sbin/init. But transit from kernel domain
803                          * if executing initializers because they might start
804                          * before /sbin/init.
805                          */
806                         domain = old_domain;
807                         break;
808                 }
809 force_child_domain:
810                 /* Normal domain transition. */
811                 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
812                          old_domain->domainname->name, candidate->name);
813                 break;
814         }
815 force_jump_domain:
816         if (!domain)
817                 domain = tomoyo_assign_domain(ee->tmp, true);
818         if (domain)
819                 retval = 0;
820         else if (reject_on_transition_failure) {
821                 printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n",
822                        ee->tmp);
823                 retval = -ENOMEM;
824         } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
825                 retval = -ENOMEM;
826         else {
827                 retval = 0;
828                 if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
829                         old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
830                         ee->r.granted = false;
831                         tomoyo_write_log(&ee->r, "%s", tomoyo_dif
832                                          [TOMOYO_DIF_TRANSITION_FAILED]);
833                         printk(KERN_WARNING
834                                "ERROR: Domain '%s' not defined.\n", ee->tmp);
835                 }
836         }
837  out:
838         if (!domain)
839                 domain = old_domain;
840         /* Update reference count on "struct tomoyo_domain_info". */
841         atomic_inc(&domain->users);
842         bprm->cred->security = domain;
843         kfree(exename.name);
844         if (!retval) {
845                 ee->r.domain = domain;
846                 retval = tomoyo_environ(ee);
847         }
848         kfree(ee->tmp);
849         kfree(ee->dump.data);
850         kfree(ee);
851         return retval;
852 }
853
854 /**
855  * tomoyo_dump_page - Dump a page to buffer.
856  *
857  * @bprm: Pointer to "struct linux_binprm".
858  * @pos:  Location to dump.
859  * @dump: Poiner to "struct tomoyo_page_dump".
860  *
861  * Returns true on success, false otherwise.
862  */
863 bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
864                       struct tomoyo_page_dump *dump)
865 {
866         struct page *page;
867
868         /* dump->data is released by tomoyo_find_next_domain(). */
869         if (!dump->data) {
870                 dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
871                 if (!dump->data)
872                         return false;
873         }
874         /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
875 #ifdef CONFIG_MMU
876         if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
877                 return false;
878 #else
879         page = bprm->page[pos / PAGE_SIZE];
880 #endif
881         if (page != dump->page) {
882                 const unsigned int offset = pos % PAGE_SIZE;
883                 /*
884                  * Maybe kmap()/kunmap() should be used here.
885                  * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
886                  * So do I.
887                  */
888                 char *kaddr = kmap_atomic(page, KM_USER0);
889
890                 dump->page = page;
891                 memcpy(dump->data + offset, kaddr + offset,
892                        PAGE_SIZE - offset);
893                 kunmap_atomic(kaddr, KM_USER0);
894         }
895         /* Same with put_arg_page(page) in fs/exec.c */
896 #ifdef CONFIG_MMU
897         put_page(page);
898 #endif
899         return true;
900 }