]> bbs.cooldavid.org Git - net-next-2.6.git/blame - security/tomoyo/domain.c
TOMOYO: Simplify policy reader.
[net-next-2.6.git] / security / tomoyo / domain.c
CommitLineData
26a2a1c9
KT
1/*
2 * security/tomoyo/domain.c
3 *
4 * Implementation of the Domain-Based Mandatory Access Control.
5 *
6 * Copyright (C) 2005-2009 NTT DATA CORPORATION
7 *
39826a1e 8 * Version: 2.2.0 2009/04/01
26a2a1c9
KT
9 *
10 */
11
12#include "common.h"
13#include "tomoyo.h"
14#include "realpath.h"
15#include <linux/binfmts.h>
16
17/* Variables definitions.*/
18
19/* The initial domain. */
20struct tomoyo_domain_info tomoyo_kernel_domain;
21
22/* The list for "struct tomoyo_domain_info". */
23LIST_HEAD(tomoyo_domain_list);
24DECLARE_RWSEM(tomoyo_domain_list_lock);
25
26/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
27struct tomoyo_domain_initializer_entry {
28 struct list_head list;
29 const struct tomoyo_path_info *domainname; /* This may be NULL */
30 const struct tomoyo_path_info *program;
31 bool is_deleted;
32 bool is_not; /* True if this entry is "no_initialize_domain". */
33 /* True if the domainname is tomoyo_get_last_name(). */
34 bool is_last_name;
35};
36
37/* Structure for "keep_domain" and "no_keep_domain" keyword. */
38struct tomoyo_domain_keeper_entry {
39 struct list_head list;
40 const struct tomoyo_path_info *domainname;
41 const struct tomoyo_path_info *program; /* This may be NULL */
42 bool is_deleted;
43 bool is_not; /* True if this entry is "no_keep_domain". */
44 /* True if the domainname is tomoyo_get_last_name(). */
45 bool is_last_name;
46};
47
48/* Structure for "alias" keyword. */
49struct tomoyo_alias_entry {
50 struct list_head list;
51 const struct tomoyo_path_info *original_name;
52 const struct tomoyo_path_info *aliased_name;
53 bool is_deleted;
54};
55
56/**
57 * tomoyo_set_domain_flag - Set or clear domain's attribute flags.
58 *
59 * @domain: Pointer to "struct tomoyo_domain_info".
60 * @is_delete: True if it is a delete request.
61 * @flags: Flags to set or clear.
62 *
63 * Returns nothing.
64 */
65void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
66 const bool is_delete, const u8 flags)
67{
68 /* We need to serialize because this is bitfield operation. */
69 static DEFINE_SPINLOCK(lock);
26a2a1c9
KT
70 spin_lock(&lock);
71 if (!is_delete)
72 domain->flags |= flags;
73 else
74 domain->flags &= ~flags;
75 spin_unlock(&lock);
26a2a1c9
KT
76}
77
78/**
79 * tomoyo_get_last_name - Get last component of a domainname.
80 *
81 * @domain: Pointer to "struct tomoyo_domain_info".
82 *
83 * Returns the last component of the domainname.
84 */
85const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
86{
87 const char *cp0 = domain->domainname->name;
88 const char *cp1 = strrchr(cp0, ' ');
89
90 if (cp1)
91 return cp1 + 1;
92 return cp0;
93}
94
95/* The list for "struct tomoyo_domain_initializer_entry". */
96static LIST_HEAD(tomoyo_domain_initializer_list);
97static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
98
99/**
100 * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
101 *
102 * @domainname: The name of domain. May be NULL.
103 * @program: The name of program.
104 * @is_not: True if it is "no_initialize_domain" entry.
105 * @is_delete: True if it is a delete request.
106 *
107 * Returns 0 on success, negative value otherwise.
108 */
109static int tomoyo_update_domain_initializer_entry(const char *domainname,
110 const char *program,
111 const bool is_not,
112 const bool is_delete)
113{
114 struct tomoyo_domain_initializer_entry *new_entry;
115 struct tomoyo_domain_initializer_entry *ptr;
116 const struct tomoyo_path_info *saved_program;
117 const struct tomoyo_path_info *saved_domainname = NULL;
118 int error = -ENOMEM;
119 bool is_last_name = false;
120
121 if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
122 return -EINVAL; /* No patterns allowed. */
123 if (domainname) {
124 if (!tomoyo_is_domain_def(domainname) &&
125 tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
126 is_last_name = true;
127 else if (!tomoyo_is_correct_domain(domainname, __func__))
128 return -EINVAL;
129 saved_domainname = tomoyo_save_name(domainname);
130 if (!saved_domainname)
131 return -ENOMEM;
132 }
133 saved_program = tomoyo_save_name(program);
134 if (!saved_program)
135 return -ENOMEM;
26a2a1c9
KT
136 down_write(&tomoyo_domain_initializer_list_lock);
137 list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
138 if (ptr->is_not != is_not ||
139 ptr->domainname != saved_domainname ||
140 ptr->program != saved_program)
141 continue;
142 ptr->is_deleted = is_delete;
143 error = 0;
144 goto out;
145 }
146 if (is_delete) {
147 error = -ENOENT;
148 goto out;
149 }
150 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
151 if (!new_entry)
152 goto out;
153 new_entry->domainname = saved_domainname;
154 new_entry->program = saved_program;
155 new_entry->is_not = is_not;
156 new_entry->is_last_name = is_last_name;
157 list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list);
158 error = 0;
159 out:
160 up_write(&tomoyo_domain_initializer_list_lock);
26a2a1c9
KT
161 return error;
162}
163
164/**
165 * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
166 *
167 * @head: Pointer to "struct tomoyo_io_buffer".
168 *
169 * Returns true on success, false otherwise.
170 */
171bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
172{
173 struct list_head *pos;
174 bool done = true;
175
176 down_read(&tomoyo_domain_initializer_list_lock);
177 list_for_each_cookie(pos, head->read_var2,
178 &tomoyo_domain_initializer_list) {
179 const char *no;
180 const char *from = "";
181 const char *domain = "";
182 struct tomoyo_domain_initializer_entry *ptr;
183 ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
184 list);
185 if (ptr->is_deleted)
186 continue;
187 no = ptr->is_not ? "no_" : "";
188 if (ptr->domainname) {
189 from = " from ";
190 domain = ptr->domainname->name;
191 }
7d2948b1
TH
192 done = tomoyo_io_printf(head,
193 "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
194 "%s%s%s\n", no, ptr->program->name,
195 from, domain);
196 if (!done)
26a2a1c9 197 break;
26a2a1c9
KT
198 }
199 up_read(&tomoyo_domain_initializer_list_lock);
200 return done;
201}
202
203/**
204 * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
205 *
206 * @data: String to parse.
207 * @is_not: True if it is "no_initialize_domain" entry.
208 * @is_delete: True if it is a delete request.
209 *
210 * Returns 0 on success, negative value otherwise.
211 */
212int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
213 const bool is_delete)
214{
215 char *cp = strstr(data, " from ");
216
217 if (cp) {
218 *cp = '\0';
219 return tomoyo_update_domain_initializer_entry(cp + 6, data,
220 is_not,
221 is_delete);
222 }
223 return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
224 is_delete);
225}
226
227/**
228 * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
229 *
230 * @domainname: The name of domain.
231 * @program: The name of program.
232 * @last_name: The last component of @domainname.
233 *
234 * Returns true if executing @program reinitializes domain transition,
235 * false otherwise.
236 */
237static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
238 domainname,
239 const struct tomoyo_path_info *program,
240 const struct tomoyo_path_info *
241 last_name)
242{
243 struct tomoyo_domain_initializer_entry *ptr;
244 bool flag = false;
245
246 down_read(&tomoyo_domain_initializer_list_lock);
247 list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
248 if (ptr->is_deleted)
249 continue;
250 if (ptr->domainname) {
251 if (!ptr->is_last_name) {
252 if (ptr->domainname != domainname)
253 continue;
254 } else {
255 if (tomoyo_pathcmp(ptr->domainname, last_name))
256 continue;
257 }
258 }
259 if (tomoyo_pathcmp(ptr->program, program))
260 continue;
261 if (ptr->is_not) {
262 flag = false;
263 break;
264 }
265 flag = true;
266 }
267 up_read(&tomoyo_domain_initializer_list_lock);
268 return flag;
269}
270
271/* The list for "struct tomoyo_domain_keeper_entry". */
272static LIST_HEAD(tomoyo_domain_keeper_list);
273static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
274
275/**
276 * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
277 *
278 * @domainname: The name of domain.
279 * @program: The name of program. May be NULL.
280 * @is_not: True if it is "no_keep_domain" entry.
281 * @is_delete: True if it is a delete request.
282 *
283 * Returns 0 on success, negative value otherwise.
284 */
285static int tomoyo_update_domain_keeper_entry(const char *domainname,
286 const char *program,
287 const bool is_not,
288 const bool is_delete)
289{
290 struct tomoyo_domain_keeper_entry *new_entry;
291 struct tomoyo_domain_keeper_entry *ptr;
292 const struct tomoyo_path_info *saved_domainname;
293 const struct tomoyo_path_info *saved_program = NULL;
26a2a1c9
KT
294 int error = -ENOMEM;
295 bool is_last_name = false;
296
297 if (!tomoyo_is_domain_def(domainname) &&
298 tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
299 is_last_name = true;
300 else if (!tomoyo_is_correct_domain(domainname, __func__))
301 return -EINVAL;
302 if (program) {
303 if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
304 return -EINVAL;
305 saved_program = tomoyo_save_name(program);
306 if (!saved_program)
307 return -ENOMEM;
308 }
309 saved_domainname = tomoyo_save_name(domainname);
310 if (!saved_domainname)
311 return -ENOMEM;
26a2a1c9
KT
312 down_write(&tomoyo_domain_keeper_list_lock);
313 list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
314 if (ptr->is_not != is_not ||
315 ptr->domainname != saved_domainname ||
316 ptr->program != saved_program)
317 continue;
318 ptr->is_deleted = is_delete;
319 error = 0;
320 goto out;
321 }
322 if (is_delete) {
323 error = -ENOENT;
324 goto out;
325 }
326 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
327 if (!new_entry)
328 goto out;
329 new_entry->domainname = saved_domainname;
330 new_entry->program = saved_program;
331 new_entry->is_not = is_not;
332 new_entry->is_last_name = is_last_name;
333 list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list);
334 error = 0;
335 out:
336 up_write(&tomoyo_domain_keeper_list_lock);
26a2a1c9
KT
337 return error;
338}
339
340/**
341 * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
342 *
343 * @data: String to parse.
344 * @is_not: True if it is "no_keep_domain" entry.
345 * @is_delete: True if it is a delete request.
346 *
347 */
348int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
349 const bool is_delete)
350{
351 char *cp = strstr(data, " from ");
352
353 if (cp) {
354 *cp = '\0';
355 return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
356 is_delete);
357 }
358 return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
359}
360
361/**
362 * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
363 *
364 * @head: Pointer to "struct tomoyo_io_buffer".
365 *
366 * Returns true on success, false otherwise.
367 */
368bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
369{
370 struct list_head *pos;
33043cbb 371 bool done = true;
26a2a1c9
KT
372
373 down_read(&tomoyo_domain_keeper_list_lock);
374 list_for_each_cookie(pos, head->read_var2,
375 &tomoyo_domain_keeper_list) {
376 struct tomoyo_domain_keeper_entry *ptr;
377 const char *no;
378 const char *from = "";
379 const char *program = "";
380
381 ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
382 if (ptr->is_deleted)
383 continue;
384 no = ptr->is_not ? "no_" : "";
385 if (ptr->program) {
386 from = " from ";
387 program = ptr->program->name;
388 }
7d2948b1
TH
389 done = tomoyo_io_printf(head,
390 "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
391 "%s%s%s\n", no, program, from,
392 ptr->domainname->name);
393 if (!done)
26a2a1c9 394 break;
26a2a1c9
KT
395 }
396 up_read(&tomoyo_domain_keeper_list_lock);
397 return done;
398}
399
400/**
401 * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
402 *
403 * @domainname: The name of domain.
404 * @program: The name of program.
405 * @last_name: The last component of @domainname.
406 *
407 * Returns true if executing @program supresses domain transition,
408 * false otherwise.
409 */
410static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
411 const struct tomoyo_path_info *program,
412 const struct tomoyo_path_info *last_name)
413{
414 struct tomoyo_domain_keeper_entry *ptr;
415 bool flag = false;
416
417 down_read(&tomoyo_domain_keeper_list_lock);
418 list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
419 if (ptr->is_deleted)
420 continue;
421 if (!ptr->is_last_name) {
422 if (ptr->domainname != domainname)
423 continue;
424 } else {
425 if (tomoyo_pathcmp(ptr->domainname, last_name))
426 continue;
427 }
428 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
429 continue;
430 if (ptr->is_not) {
431 flag = false;
432 break;
433 }
434 flag = true;
435 }
436 up_read(&tomoyo_domain_keeper_list_lock);
437 return flag;
438}
439
440/* The list for "struct tomoyo_alias_entry". */
441static LIST_HEAD(tomoyo_alias_list);
442static DECLARE_RWSEM(tomoyo_alias_list_lock);
443
444/**
445 * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
446 *
447 * @original_name: The original program's real name.
448 * @aliased_name: The symbolic program's symbolic link's name.
449 * @is_delete: True if it is a delete request.
450 *
451 * Returns 0 on success, negative value otherwise.
452 */
453static int tomoyo_update_alias_entry(const char *original_name,
454 const char *aliased_name,
455 const bool is_delete)
456{
457 struct tomoyo_alias_entry *new_entry;
458 struct tomoyo_alias_entry *ptr;
459 const struct tomoyo_path_info *saved_original_name;
460 const struct tomoyo_path_info *saved_aliased_name;
461 int error = -ENOMEM;
462
463 if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
464 !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
465 return -EINVAL; /* No patterns allowed. */
466 saved_original_name = tomoyo_save_name(original_name);
467 saved_aliased_name = tomoyo_save_name(aliased_name);
468 if (!saved_original_name || !saved_aliased_name)
469 return -ENOMEM;
26a2a1c9
KT
470 down_write(&tomoyo_alias_list_lock);
471 list_for_each_entry(ptr, &tomoyo_alias_list, list) {
472 if (ptr->original_name != saved_original_name ||
473 ptr->aliased_name != saved_aliased_name)
474 continue;
475 ptr->is_deleted = is_delete;
476 error = 0;
477 goto out;
478 }
479 if (is_delete) {
480 error = -ENOENT;
481 goto out;
482 }
483 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
484 if (!new_entry)
485 goto out;
486 new_entry->original_name = saved_original_name;
487 new_entry->aliased_name = saved_aliased_name;
488 list_add_tail(&new_entry->list, &tomoyo_alias_list);
489 error = 0;
490 out:
491 up_write(&tomoyo_alias_list_lock);
26a2a1c9
KT
492 return error;
493}
494
495/**
496 * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
497 *
498 * @head: Pointer to "struct tomoyo_io_buffer".
499 *
500 * Returns true on success, false otherwise.
501 */
502bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
503{
504 struct list_head *pos;
505 bool done = true;
506
507 down_read(&tomoyo_alias_list_lock);
508 list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
509 struct tomoyo_alias_entry *ptr;
510
511 ptr = list_entry(pos, struct tomoyo_alias_entry, list);
512 if (ptr->is_deleted)
513 continue;
7d2948b1
TH
514 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
515 ptr->original_name->name,
516 ptr->aliased_name->name);
517 if (!done)
26a2a1c9 518 break;
26a2a1c9
KT
519 }
520 up_read(&tomoyo_alias_list_lock);
521 return done;
522}
523
524/**
525 * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
526 *
527 * @data: String to parse.
528 * @is_delete: True if it is a delete request.
529 *
530 * Returns 0 on success, negative value otherwise.
531 */
532int tomoyo_write_alias_policy(char *data, const bool is_delete)
533{
534 char *cp = strchr(data, ' ');
535
536 if (!cp)
537 return -EINVAL;
538 *cp++ = '\0';
539 return tomoyo_update_alias_entry(data, cp, is_delete);
540}
541
a0558fc3 542/* Domain create/delete handler. */
26a2a1c9
KT
543
544/**
545 * tomoyo_delete_domain - Delete a domain.
546 *
547 * @domainname: The name of domain.
548 *
549 * Returns 0.
550 */
551int tomoyo_delete_domain(char *domainname)
552{
553 struct tomoyo_domain_info *domain;
554 struct tomoyo_path_info name;
555
556 name.name = domainname;
557 tomoyo_fill_path_info(&name);
26a2a1c9 558 down_write(&tomoyo_domain_list_lock);
26a2a1c9
KT
559 /* Is there an active domain? */
560 list_for_each_entry(domain, &tomoyo_domain_list, list) {
26a2a1c9
KT
561 /* Never delete tomoyo_kernel_domain */
562 if (domain == &tomoyo_kernel_domain)
563 continue;
564 if (domain->is_deleted ||
565 tomoyo_pathcmp(domain->domainname, &name))
566 continue;
a0558fc3 567 domain->is_deleted = true;
26a2a1c9
KT
568 break;
569 }
570 up_write(&tomoyo_domain_list_lock);
26a2a1c9
KT
571 return 0;
572}
573
26a2a1c9
KT
574/**
575 * tomoyo_find_or_assign_new_domain - Create a domain.
576 *
577 * @domainname: The name of domain.
578 * @profile: Profile number to assign if the domain was newly created.
579 *
580 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
581 */
582struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
583 domainname,
584 const u8 profile)
585{
586 struct tomoyo_domain_info *domain = NULL;
587 const struct tomoyo_path_info *saved_domainname;
588
26a2a1c9
KT
589 down_write(&tomoyo_domain_list_lock);
590 domain = tomoyo_find_domain(domainname);
591 if (domain)
592 goto out;
593 if (!tomoyo_is_correct_domain(domainname, __func__))
594 goto out;
595 saved_domainname = tomoyo_save_name(domainname);
596 if (!saved_domainname)
597 goto out;
598 /* Can I reuse memory of deleted domain? */
599 list_for_each_entry(domain, &tomoyo_domain_list, list) {
600 struct task_struct *p;
601 struct tomoyo_acl_info *ptr;
602 bool flag;
603 if (!domain->is_deleted ||
604 domain->domainname != saved_domainname)
605 continue;
606 flag = false;
26a2a1c9
KT
607 read_lock(&tasklist_lock);
608 for_each_process(p) {
609 if (tomoyo_real_domain(p) != domain)
610 continue;
611 flag = true;
612 break;
613 }
614 read_unlock(&tasklist_lock);
26a2a1c9
KT
615 if (flag)
616 continue;
26a2a1c9
KT
617 list_for_each_entry(ptr, &domain->acl_info_list, list) {
618 ptr->type |= TOMOYO_ACL_DELETED;
619 }
620 tomoyo_set_domain_flag(domain, true, domain->flags);
621 domain->profile = profile;
622 domain->quota_warned = false;
623 mb(); /* Avoid out-of-order execution. */
a0558fc3 624 domain->is_deleted = false;
26a2a1c9
KT
625 goto out;
626 }
627 /* No memory reusable. Create using new memory. */
628 domain = tomoyo_alloc_element(sizeof(*domain));
629 if (domain) {
630 INIT_LIST_HEAD(&domain->acl_info_list);
631 domain->domainname = saved_domainname;
632 domain->profile = profile;
633 list_add_tail(&domain->list, &tomoyo_domain_list);
634 }
635 out:
636 up_write(&tomoyo_domain_list_lock);
26a2a1c9
KT
637 return domain;
638}
639
640/**
641 * tomoyo_find_next_domain - Find a domain.
642 *
643 * @bprm: Pointer to "struct linux_binprm".
644 * @next_domain: Pointer to pointer to "struct tomoyo_domain_info".
645 *
646 * Returns 0 on success, negative value otherwise.
647 */
648int tomoyo_find_next_domain(struct linux_binprm *bprm,
649 struct tomoyo_domain_info **next_domain)
650{
651 /*
652 * This function assumes that the size of buffer returned by
653 * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
654 */
655 struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
656 struct tomoyo_domain_info *old_domain = tomoyo_domain();
657 struct tomoyo_domain_info *domain = NULL;
658 const char *old_domain_name = old_domain->domainname->name;
659 const char *original_name = bprm->filename;
660 char *new_domain_name = NULL;
661 char *real_program_name = NULL;
662 char *symlink_program_name = NULL;
663 const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
664 const bool is_enforce = (mode == 3);
665 int retval = -ENOMEM;
666 struct tomoyo_path_info r; /* real name */
667 struct tomoyo_path_info s; /* symlink name */
668 struct tomoyo_path_info l; /* last name */
669 static bool initialized;
670
671 if (!tmp)
672 goto out;
673
674 if (!initialized) {
675 /*
676 * Built-in initializers. This is needed because policies are
677 * not loaded until starting /sbin/init.
678 */
679 tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
680 false, false);
681 tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
682 false, false);
683 initialized = true;
684 }
685
686 /* Get tomoyo_realpath of program. */
687 retval = -ENOENT;
688 /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
689 real_program_name = tomoyo_realpath(original_name);
690 if (!real_program_name)
691 goto out;
692 /* Get tomoyo_realpath of symbolic link. */
693 symlink_program_name = tomoyo_realpath_nofollow(original_name);
694 if (!symlink_program_name)
695 goto out;
696
697 r.name = real_program_name;
698 tomoyo_fill_path_info(&r);
699 s.name = symlink_program_name;
700 tomoyo_fill_path_info(&s);
701 l.name = tomoyo_get_last_name(old_domain);
702 tomoyo_fill_path_info(&l);
703
704 /* Check 'alias' directive. */
705 if (tomoyo_pathcmp(&r, &s)) {
706 struct tomoyo_alias_entry *ptr;
707 /* Is this program allowed to be called via symbolic links? */
708 down_read(&tomoyo_alias_list_lock);
709 list_for_each_entry(ptr, &tomoyo_alias_list, list) {
710 if (ptr->is_deleted ||
711 tomoyo_pathcmp(&r, ptr->original_name) ||
712 tomoyo_pathcmp(&s, ptr->aliased_name))
713 continue;
714 memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
715 strncpy(real_program_name, ptr->aliased_name->name,
716 TOMOYO_MAX_PATHNAME_LEN - 1);
717 tomoyo_fill_path_info(&r);
718 break;
719 }
720 up_read(&tomoyo_alias_list_lock);
721 }
722
723 /* Check execute permission. */
724 retval = tomoyo_check_exec_perm(old_domain, &r, tmp);
725 if (retval < 0)
726 goto out;
727
728 new_domain_name = tmp->buffer;
729 if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
730 /* Transit to the child of tomoyo_kernel_domain domain. */
731 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
732 TOMOYO_ROOT_NAME " " "%s", real_program_name);
733 } else if (old_domain == &tomoyo_kernel_domain &&
734 !tomoyo_policy_loaded) {
735 /*
736 * Needn't to transit from kernel domain before starting
737 * /sbin/init. But transit from kernel domain if executing
738 * initializers because they might start before /sbin/init.
739 */
740 domain = old_domain;
741 } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
742 /* Keep current domain. */
743 domain = old_domain;
744 } else {
745 /* Normal domain transition. */
746 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
747 "%s %s", old_domain_name, real_program_name);
748 }
749 if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
750 goto done;
751 down_read(&tomoyo_domain_list_lock);
752 domain = tomoyo_find_domain(new_domain_name);
753 up_read(&tomoyo_domain_list_lock);
754 if (domain)
755 goto done;
756 if (is_enforce)
757 goto done;
758 domain = tomoyo_find_or_assign_new_domain(new_domain_name,
759 old_domain->profile);
760 done:
761 if (domain)
762 goto out;
763 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
764 new_domain_name);
765 if (is_enforce)
766 retval = -EPERM;
767 else
768 tomoyo_set_domain_flag(old_domain, false,
769 TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
770 out:
771 tomoyo_free(real_program_name);
772 tomoyo_free(symlink_program_name);
773 *next_domain = domain ? domain : old_domain;
774 tomoyo_free(tmp);
775 return retval;
776}