1
2
3
4
5
6
7
8
9
10
11
12#include "common.h"
13#include "tomoyo.h"
14#include "realpath.h"
15#include <linux/binfmts.h>
16
17
18
19
20struct tomoyo_domain_info tomoyo_kernel_domain;
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60LIST_HEAD(tomoyo_domain_list);
61DECLARE_RWSEM(tomoyo_domain_list_lock);
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79struct tomoyo_domain_initializer_entry {
80 struct list_head list;
81 const struct tomoyo_path_info *domainname;
82 const struct tomoyo_path_info *program;
83 bool is_deleted;
84 bool is_not;
85
86 bool is_last_name;
87};
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106struct tomoyo_domain_keeper_entry {
107 struct list_head list;
108 const struct tomoyo_path_info *domainname;
109 const struct tomoyo_path_info *program;
110 bool is_deleted;
111 bool is_not;
112
113 bool is_last_name;
114};
115
116
117
118
119
120
121
122
123
124
125
126struct tomoyo_alias_entry {
127 struct list_head list;
128 const struct tomoyo_path_info *original_name;
129 const struct tomoyo_path_info *aliased_name;
130 bool is_deleted;
131};
132
133
134
135
136
137
138
139
140
141
142void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
143 const bool is_delete, const u8 flags)
144{
145
146 static DEFINE_SPINLOCK(lock);
147 spin_lock(&lock);
148 if (!is_delete)
149 domain->flags |= flags;
150 else
151 domain->flags &= ~flags;
152 spin_unlock(&lock);
153}
154
155
156
157
158
159
160
161
162const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
163{
164 const char *cp0 = domain->domainname->name;
165 const char *cp1 = strrchr(cp0, ' ');
166
167 if (cp1)
168 return cp1 + 1;
169 return cp0;
170}
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208static LIST_HEAD(tomoyo_domain_initializer_list);
209static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
210
211
212
213
214
215
216
217
218
219
220
221static int tomoyo_update_domain_initializer_entry(const char *domainname,
222 const char *program,
223 const bool is_not,
224 const bool is_delete)
225{
226 struct tomoyo_domain_initializer_entry *new_entry;
227 struct tomoyo_domain_initializer_entry *ptr;
228 const struct tomoyo_path_info *saved_program;
229 const struct tomoyo_path_info *saved_domainname = NULL;
230 int error = -ENOMEM;
231 bool is_last_name = false;
232
233 if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
234 return -EINVAL;
235 if (domainname) {
236 if (!tomoyo_is_domain_def(domainname) &&
237 tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
238 is_last_name = true;
239 else if (!tomoyo_is_correct_domain(domainname, __func__))
240 return -EINVAL;
241 saved_domainname = tomoyo_save_name(domainname);
242 if (!saved_domainname)
243 return -ENOMEM;
244 }
245 saved_program = tomoyo_save_name(program);
246 if (!saved_program)
247 return -ENOMEM;
248 down_write(&tomoyo_domain_initializer_list_lock);
249 list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
250 if (ptr->is_not != is_not ||
251 ptr->domainname != saved_domainname ||
252 ptr->program != saved_program)
253 continue;
254 ptr->is_deleted = is_delete;
255 error = 0;
256 goto out;
257 }
258 if (is_delete) {
259 error = -ENOENT;
260 goto out;
261 }
262 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
263 if (!new_entry)
264 goto out;
265 new_entry->domainname = saved_domainname;
266 new_entry->program = saved_program;
267 new_entry->is_not = is_not;
268 new_entry->is_last_name = is_last_name;
269 list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list);
270 error = 0;
271 out:
272 up_write(&tomoyo_domain_initializer_list_lock);
273 return error;
274}
275
276
277
278
279
280
281
282
283bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
284{
285 struct list_head *pos;
286 bool done = true;
287
288 down_read(&tomoyo_domain_initializer_list_lock);
289 list_for_each_cookie(pos, head->read_var2,
290 &tomoyo_domain_initializer_list) {
291 const char *no;
292 const char *from = "";
293 const char *domain = "";
294 struct tomoyo_domain_initializer_entry *ptr;
295 ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
296 list);
297 if (ptr->is_deleted)
298 continue;
299 no = ptr->is_not ? "no_" : "";
300 if (ptr->domainname) {
301 from = " from ";
302 domain = ptr->domainname->name;
303 }
304 done = tomoyo_io_printf(head,
305 "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
306 "%s%s%s\n", no, ptr->program->name,
307 from, domain);
308 if (!done)
309 break;
310 }
311 up_read(&tomoyo_domain_initializer_list_lock);
312 return done;
313}
314
315
316
317
318
319
320
321
322
323
324int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
325 const bool is_delete)
326{
327 char *cp = strstr(data, " from ");
328
329 if (cp) {
330 *cp = '\0';
331 return tomoyo_update_domain_initializer_entry(cp + 6, data,
332 is_not,
333 is_delete);
334 }
335 return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
336 is_delete);
337}
338
339
340
341
342
343
344
345
346
347
348
349static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
350 domainname,
351 const struct tomoyo_path_info *program,
352 const struct tomoyo_path_info *
353 last_name)
354{
355 struct tomoyo_domain_initializer_entry *ptr;
356 bool flag = false;
357
358 down_read(&tomoyo_domain_initializer_list_lock);
359 list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
360 if (ptr->is_deleted)
361 continue;
362 if (ptr->domainname) {
363 if (!ptr->is_last_name) {
364 if (ptr->domainname != domainname)
365 continue;
366 } else {
367 if (tomoyo_pathcmp(ptr->domainname, last_name))
368 continue;
369 }
370 }
371 if (tomoyo_pathcmp(ptr->program, program))
372 continue;
373 if (ptr->is_not) {
374 flag = false;
375 break;
376 }
377 flag = true;
378 }
379 up_read(&tomoyo_domain_initializer_list_lock);
380 return flag;
381}
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421static LIST_HEAD(tomoyo_domain_keeper_list);
422static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
423
424
425
426
427
428
429
430
431
432
433
434static int tomoyo_update_domain_keeper_entry(const char *domainname,
435 const char *program,
436 const bool is_not,
437 const bool is_delete)
438{
439 struct tomoyo_domain_keeper_entry *new_entry;
440 struct tomoyo_domain_keeper_entry *ptr;
441 const struct tomoyo_path_info *saved_domainname;
442 const struct tomoyo_path_info *saved_program = NULL;
443 int error = -ENOMEM;
444 bool is_last_name = false;
445
446 if (!tomoyo_is_domain_def(domainname) &&
447 tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
448 is_last_name = true;
449 else if (!tomoyo_is_correct_domain(domainname, __func__))
450 return -EINVAL;
451 if (program) {
452 if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
453 return -EINVAL;
454 saved_program = tomoyo_save_name(program);
455 if (!saved_program)
456 return -ENOMEM;
457 }
458 saved_domainname = tomoyo_save_name(domainname);
459 if (!saved_domainname)
460 return -ENOMEM;
461 down_write(&tomoyo_domain_keeper_list_lock);
462 list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
463 if (ptr->is_not != is_not ||
464 ptr->domainname != saved_domainname ||
465 ptr->program != saved_program)
466 continue;
467 ptr->is_deleted = is_delete;
468 error = 0;
469 goto out;
470 }
471 if (is_delete) {
472 error = -ENOENT;
473 goto out;
474 }
475 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
476 if (!new_entry)
477 goto out;
478 new_entry->domainname = saved_domainname;
479 new_entry->program = saved_program;
480 new_entry->is_not = is_not;
481 new_entry->is_last_name = is_last_name;
482 list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list);
483 error = 0;
484 out:
485 up_write(&tomoyo_domain_keeper_list_lock);
486 return error;
487}
488
489
490
491
492
493
494
495
496
497int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
498 const bool is_delete)
499{
500 char *cp = strstr(data, " from ");
501
502 if (cp) {
503 *cp = '\0';
504 return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
505 is_delete);
506 }
507 return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
508}
509
510
511
512
513
514
515
516
517bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
518{
519 struct list_head *pos;
520 bool done = true;
521
522 down_read(&tomoyo_domain_keeper_list_lock);
523 list_for_each_cookie(pos, head->read_var2,
524 &tomoyo_domain_keeper_list) {
525 struct tomoyo_domain_keeper_entry *ptr;
526 const char *no;
527 const char *from = "";
528 const char *program = "";
529
530 ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
531 if (ptr->is_deleted)
532 continue;
533 no = ptr->is_not ? "no_" : "";
534 if (ptr->program) {
535 from = " from ";
536 program = ptr->program->name;
537 }
538 done = tomoyo_io_printf(head,
539 "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
540 "%s%s%s\n", no, program, from,
541 ptr->domainname->name);
542 if (!done)
543 break;
544 }
545 up_read(&tomoyo_domain_keeper_list_lock);
546 return done;
547}
548
549
550
551
552
553
554
555
556
557
558
559static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
560 const struct tomoyo_path_info *program,
561 const struct tomoyo_path_info *last_name)
562{
563 struct tomoyo_domain_keeper_entry *ptr;
564 bool flag = false;
565
566 down_read(&tomoyo_domain_keeper_list_lock);
567 list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
568 if (ptr->is_deleted)
569 continue;
570 if (!ptr->is_last_name) {
571 if (ptr->domainname != domainname)
572 continue;
573 } else {
574 if (tomoyo_pathcmp(ptr->domainname, last_name))
575 continue;
576 }
577 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
578 continue;
579 if (ptr->is_not) {
580 flag = false;
581 break;
582 }
583 flag = true;
584 }
585 up_read(&tomoyo_domain_keeper_list_lock);
586 return flag;
587}
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619static LIST_HEAD(tomoyo_alias_list);
620static DECLARE_RWSEM(tomoyo_alias_list_lock);
621
622
623
624
625
626
627
628
629
630
631static int tomoyo_update_alias_entry(const char *original_name,
632 const char *aliased_name,
633 const bool is_delete)
634{
635 struct tomoyo_alias_entry *new_entry;
636 struct tomoyo_alias_entry *ptr;
637 const struct tomoyo_path_info *saved_original_name;
638 const struct tomoyo_path_info *saved_aliased_name;
639 int error = -ENOMEM;
640
641 if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
642 !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
643 return -EINVAL;
644 saved_original_name = tomoyo_save_name(original_name);
645 saved_aliased_name = tomoyo_save_name(aliased_name);
646 if (!saved_original_name || !saved_aliased_name)
647 return -ENOMEM;
648 down_write(&tomoyo_alias_list_lock);
649 list_for_each_entry(ptr, &tomoyo_alias_list, list) {
650 if (ptr->original_name != saved_original_name ||
651 ptr->aliased_name != saved_aliased_name)
652 continue;
653 ptr->is_deleted = is_delete;
654 error = 0;
655 goto out;
656 }
657 if (is_delete) {
658 error = -ENOENT;
659 goto out;
660 }
661 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
662 if (!new_entry)
663 goto out;
664 new_entry->original_name = saved_original_name;
665 new_entry->aliased_name = saved_aliased_name;
666 list_add_tail(&new_entry->list, &tomoyo_alias_list);
667 error = 0;
668 out:
669 up_write(&tomoyo_alias_list_lock);
670 return error;
671}
672
673
674
675
676
677
678
679
680bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
681{
682 struct list_head *pos;
683 bool done = true;
684
685 down_read(&tomoyo_alias_list_lock);
686 list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
687 struct tomoyo_alias_entry *ptr;
688
689 ptr = list_entry(pos, struct tomoyo_alias_entry, list);
690 if (ptr->is_deleted)
691 continue;
692 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
693 ptr->original_name->name,
694 ptr->aliased_name->name);
695 if (!done)
696 break;
697 }
698 up_read(&tomoyo_alias_list_lock);
699 return done;
700}
701
702
703
704
705
706
707
708
709
710int tomoyo_write_alias_policy(char *data, const bool is_delete)
711{
712 char *cp = strchr(data, ' ');
713
714 if (!cp)
715 return -EINVAL;
716 *cp++ = '\0';
717 return tomoyo_update_alias_entry(data, cp, is_delete);
718}
719
720
721
722
723
724
725
726
727
728struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
729 domainname,
730 const u8 profile)
731{
732 struct tomoyo_domain_info *domain = NULL;
733 const struct tomoyo_path_info *saved_domainname;
734
735 down_write(&tomoyo_domain_list_lock);
736 domain = tomoyo_find_domain(domainname);
737 if (domain)
738 goto out;
739 if (!tomoyo_is_correct_domain(domainname, __func__))
740 goto out;
741 saved_domainname = tomoyo_save_name(domainname);
742 if (!saved_domainname)
743 goto out;
744
745 list_for_each_entry(domain, &tomoyo_domain_list, list) {
746 struct task_struct *p;
747 struct tomoyo_acl_info *ptr;
748 bool flag;
749 if (!domain->is_deleted ||
750 domain->domainname != saved_domainname)
751 continue;
752 flag = false;
753 read_lock(&tasklist_lock);
754 for_each_process(p) {
755 if (tomoyo_real_domain(p) != domain)
756 continue;
757 flag = true;
758 break;
759 }
760 read_unlock(&tasklist_lock);
761 if (flag)
762 continue;
763 list_for_each_entry(ptr, &domain->acl_info_list, list) {
764 ptr->type |= TOMOYO_ACL_DELETED;
765 }
766 tomoyo_set_domain_flag(domain, true, domain->flags);
767 domain->profile = profile;
768 domain->quota_warned = false;
769 mb();
770 domain->is_deleted = false;
771 goto out;
772 }
773
774 domain = tomoyo_alloc_element(sizeof(*domain));
775 if (domain) {
776 INIT_LIST_HEAD(&domain->acl_info_list);
777 domain->domainname = saved_domainname;
778 domain->profile = profile;
779 list_add_tail(&domain->list, &tomoyo_domain_list);
780 }
781 out:
782 up_write(&tomoyo_domain_list_lock);
783 return domain;
784}
785
786
787
788
789
790
791
792
793int tomoyo_find_next_domain(struct linux_binprm *bprm)
794{
795
796
797
798
799 struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
800 struct tomoyo_domain_info *old_domain = tomoyo_domain();
801 struct tomoyo_domain_info *domain = NULL;
802 const char *old_domain_name = old_domain->domainname->name;
803 const char *original_name = bprm->filename;
804 char *new_domain_name = NULL;
805 char *real_program_name = NULL;
806 char *symlink_program_name = NULL;
807 const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
808 const bool is_enforce = (mode == 3);
809 int retval = -ENOMEM;
810 struct tomoyo_path_info r;
811 struct tomoyo_path_info s;
812 struct tomoyo_path_info l;
813 static bool initialized;
814
815 if (!tmp)
816 goto out;
817
818 if (!initialized) {
819
820
821
822
823 tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
824 false, false);
825 tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
826 false, false);
827 initialized = true;
828 }
829
830
831 retval = -ENOENT;
832
833 real_program_name = tomoyo_realpath(original_name);
834 if (!real_program_name)
835 goto out;
836
837 symlink_program_name = tomoyo_realpath_nofollow(original_name);
838 if (!symlink_program_name)
839 goto out;
840
841 r.name = real_program_name;
842 tomoyo_fill_path_info(&r);
843 s.name = symlink_program_name;
844 tomoyo_fill_path_info(&s);
845 l.name = tomoyo_get_last_name(old_domain);
846 tomoyo_fill_path_info(&l);
847
848
849 if (tomoyo_pathcmp(&r, &s)) {
850 struct tomoyo_alias_entry *ptr;
851
852 down_read(&tomoyo_alias_list_lock);
853 list_for_each_entry(ptr, &tomoyo_alias_list, list) {
854 if (ptr->is_deleted ||
855 tomoyo_pathcmp(&r, ptr->original_name) ||
856 tomoyo_pathcmp(&s, ptr->aliased_name))
857 continue;
858 memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
859 strncpy(real_program_name, ptr->aliased_name->name,
860 TOMOYO_MAX_PATHNAME_LEN - 1);
861 tomoyo_fill_path_info(&r);
862 break;
863 }
864 up_read(&tomoyo_alias_list_lock);
865 }
866
867
868 retval = tomoyo_check_exec_perm(old_domain, &r);
869 if (retval < 0)
870 goto out;
871
872 new_domain_name = tmp->buffer;
873 if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
874
875 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
876 TOMOYO_ROOT_NAME " " "%s", real_program_name);
877 } else if (old_domain == &tomoyo_kernel_domain &&
878 !tomoyo_policy_loaded) {
879
880
881
882
883
884 domain = old_domain;
885 } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
886
887 domain = old_domain;
888 } else {
889
890 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
891 "%s %s", old_domain_name, real_program_name);
892 }
893 if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
894 goto done;
895 down_read(&tomoyo_domain_list_lock);
896 domain = tomoyo_find_domain(new_domain_name);
897 up_read(&tomoyo_domain_list_lock);
898 if (domain)
899 goto done;
900 if (is_enforce)
901 goto done;
902 domain = tomoyo_find_or_assign_new_domain(new_domain_name,
903 old_domain->profile);
904 done:
905 if (domain)
906 goto out;
907 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
908 new_domain_name);
909 if (is_enforce)
910 retval = -EPERM;
911 else
912 tomoyo_set_domain_flag(old_domain, false,
913 TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
914 out:
915 if (!domain)
916 domain = old_domain;
917 bprm->cred->security = domain;
918 tomoyo_free(real_program_name);
919 tomoyo_free(symlink_program_name);
920 tomoyo_free(tmp);
921 return retval;
922}
923