オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Contents of /branches/ccs-patch/fs/tomoyo_domain.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1747 - (show annotations) (download) (as text)
Fri Oct 24 04:07:03 2008 UTC (15 years, 7 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/tomoyo_domain.c
File MIME type: text/x-csrc
File size: 46869 byte(s)


1 /*
2 * fs/tomoyo_domain.c
3 *
4 * Implementation of the Domain-Based Mandatory Access Control.
5 *
6 * Copyright (C) 2005-2008 NTT DATA CORPORATION
7 *
8 * Version: 1.6.5-pre 2008/10/20
9 *
10 * This file is applicable to both 2.4.30 and 2.6.11 and later.
11 * See README.ccs for ChangeLog.
12 *
13 */
14
15 #include <linux/ccs_common.h>
16 #include <linux/tomoyo.h>
17 #include <linux/realpath.h>
18 #include <linux/highmem.h>
19 #include <linux/binfmts.h>
20 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
21 #include <linux/namei.h>
22 #include <linux/mount.h>
23 #endif
24
25 /* For compatibility with older kernels. */
26 #ifndef for_each_process
27 #define for_each_process for_each_task
28 #endif
29
30 /* Variables definitions.*/
31
32 /* The initial domain. */
33 struct domain_info KERNEL_DOMAIN;
34
35 /* The list for "struct domain_info". */
36 LIST1_HEAD(domain_list);
37
38 #ifdef CONFIG_TOMOYO
39
40 /* Domain creation lock. */
41 static DEFINE_MUTEX(domain_list_lock);
42
43 /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
44 struct domain_initializer_entry {
45 struct list1_head list;
46 const struct path_info *domainname; /* This may be NULL */
47 const struct path_info *program;
48 bool is_deleted;
49 bool is_not; /* True if this entry is "no_initialize_domain". */
50 bool is_last_name; /* True if the domainname is ccs_get_last_name(). */
51 };
52
53 /* Structure for "keep_domain" and "no_keep_domain" keyword. */
54 struct domain_keeper_entry {
55 struct list1_head list;
56 const struct path_info *domainname;
57 const struct path_info *program; /* This may be NULL */
58 bool is_deleted;
59 bool is_not; /* True if this entry is "no_keep_domain". */
60 bool is_last_name; /* True if the domainname is ccs_get_last_name(). */
61 };
62
63 /* Structure for "aggregator" keyword. */
64 struct aggregator_entry {
65 struct list1_head list;
66 const struct path_info *original_name;
67 const struct path_info *aggregated_name;
68 bool is_deleted;
69 };
70
71 /* Structure for "alias" keyword. */
72 struct alias_entry {
73 struct list1_head list;
74 const struct path_info *original_name;
75 const struct path_info *aliased_name;
76 bool is_deleted;
77 };
78
79 /**
80 * ccs_set_domain_flag - Set or clear domain's attribute flags.
81 *
82 * @domain: Pointer to "struct domain_info".
83 * @is_delete: True if it is a delete request.
84 * @flags: Flags to set or clear.
85 *
86 * Returns nothing.
87 */
88 void ccs_set_domain_flag(struct domain_info *domain, const bool is_delete,
89 const u8 flags)
90 {
91 /* We need to serialize because this is bitfield operation. */
92 static DEFINE_SPINLOCK(lock);
93 /***** CRITICAL SECTION START *****/
94 spin_lock(&lock);
95 if (!is_delete)
96 domain->flags |= flags;
97 else
98 domain->flags &= ~flags;
99 spin_unlock(&lock);
100 /***** CRITICAL SECTION END *****/
101 }
102
103 /**
104 * ccs_get_last_name - Get last component of a domainname.
105 *
106 * @domain: Pointer to "struct domain_info".
107 *
108 * Returns the last component of the domainname.
109 */
110 const char *ccs_get_last_name(const struct domain_info *domain)
111 {
112 const char *cp0 = domain->domainname->name;
113 const char *cp1 = strrchr(cp0, ' ');
114 if (cp1)
115 return cp1 + 1;
116 return cp0;
117 }
118
119 /**
120 * ccs_add_domain_acl - Add the given ACL to the given domain.
121 *
122 * @domain: Pointer to "struct domain_info". May be NULL.
123 * @acl: Pointer to "struct acl_info".
124 *
125 * Returns 0.
126 */
127 int ccs_add_domain_acl(struct domain_info *domain, struct acl_info *acl)
128 {
129 if (domain) {
130 /*
131 * We need to serialize because this function is called by
132 * various update functions.
133 */
134 static DEFINE_SPINLOCK(lock);
135 /***** CRITICAL SECTION START *****/
136 spin_lock(&lock);
137 list1_add_tail_mb(&acl->list, &domain->acl_info_list);
138 spin_unlock(&lock);
139 /***** CRITICAL SECTION END *****/
140 } else {
141 acl->type &= ~ACL_DELETED;
142 }
143 ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
144 return 0;
145 }
146
147 /**
148 * ccs_del_domain_acl - Delete the given ACL from the domain.
149 *
150 * @acl: Pointer to "struct acl_info". May be NULL.
151 *
152 * Returns 0.
153 */
154 int ccs_del_domain_acl(struct acl_info *acl)
155 {
156 if (acl)
157 acl->type |= ACL_DELETED;
158 ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
159 return 0;
160 }
161
162 /**
163 * audit_execute_handler_log - Audit execute_handler log.
164 *
165 * @is_default: True if it is "execute_handler" log.
166 * @handler: The realpath of the handler.
167 * @bprm: Pointer to "struct linux_binprm".
168 *
169 * Returns 0 on success, negative value otherwise.
170 */
171 static int audit_execute_handler_log(const bool is_default,
172 const char *handler,
173 struct linux_binprm *bprm)
174 {
175 struct ccs_request_info r;
176 ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_FILE);
177 r.bprm = bprm;
178 return ccs_write_audit_log(true, &r, "%s %s\n",
179 is_default ? KEYWORD_EXECUTE_HANDLER :
180 KEYWORD_DENIED_EXECUTE_HANDLER, handler);
181 }
182
183 /**
184 * audit_domain_creation_log - Audit domain creation log.
185 *
186 * @domain: Pointer to "struct domain_info".
187 *
188 * Returns 0 on success, negative value otherwise.
189 */
190 static int audit_domain_creation_log(struct domain_info *domain)
191 {
192 struct ccs_request_info r;
193 ccs_init_request_info(&r, domain, CCS_TOMOYO_MAC_FOR_FILE);
194 return ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);
195 }
196
197 /* The list for "struct domain_initializer_entry". */
198 static LIST1_HEAD(domain_initializer_list);
199
200 /**
201 * update_domain_initializer_entry - Update "struct domain_initializer_entry" list.
202 *
203 * @domainname: The name of domain. May be NULL.
204 * @program: The name of program.
205 * @is_not: True if it is "no_initialize_domain" entry.
206 * @is_delete: True if it is a delete request.
207 *
208 * Returns 0 on success, negative value otherwise.
209 */
210 static int update_domain_initializer_entry(const char *domainname,
211 const char *program,
212 const bool is_not,
213 const bool is_delete)
214 {
215 struct domain_initializer_entry *new_entry;
216 struct domain_initializer_entry *ptr;
217 static DEFINE_MUTEX(lock);
218 const struct path_info *saved_program;
219 const struct path_info *saved_domainname = NULL;
220 int error = -ENOMEM;
221 bool is_last_name = false;
222 if (!ccs_is_correct_path(program, 1, -1, -1, __func__))
223 return -EINVAL; /* No patterns allowed. */
224 if (domainname) {
225 if (!ccs_is_domain_def(domainname) &&
226 ccs_is_correct_path(domainname, 1, -1, -1, __func__))
227 is_last_name = true;
228 else if (!ccs_is_correct_domain(domainname, __func__))
229 return -EINVAL;
230 saved_domainname = ccs_save_name(domainname);
231 if (!saved_domainname)
232 return -ENOMEM;
233 }
234 saved_program = ccs_save_name(program);
235 if (!saved_program)
236 return -ENOMEM;
237 mutex_lock(&lock);
238 list1_for_each_entry(ptr, &domain_initializer_list, list) {
239 if (ptr->is_not != is_not ||
240 ptr->domainname != saved_domainname ||
241 ptr->program != saved_program)
242 continue;
243 ptr->is_deleted = is_delete;
244 error = 0;
245 goto out;
246 }
247 if (is_delete) {
248 error = -ENOENT;
249 goto out;
250 }
251 new_entry = ccs_alloc_element(sizeof(*new_entry));
252 if (!new_entry)
253 goto out;
254 new_entry->domainname = saved_domainname;
255 new_entry->program = saved_program;
256 new_entry->is_not = is_not;
257 new_entry->is_last_name = is_last_name;
258 list1_add_tail_mb(&new_entry->list, &domain_initializer_list);
259 error = 0;
260 out:
261 mutex_unlock(&lock);
262 ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
263 return error;
264 }
265
266 /**
267 * ccs_read_domain_initializer_policy - Read "struct domain_initializer_entry" list.
268 *
269 * @head: Pointer to "struct ccs_io_buffer".
270 *
271 * Returns true on success, false otherwise.
272 */
273 bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
274 {
275 struct list1_head *pos;
276 list1_for_each_cookie(pos, head->read_var2, &domain_initializer_list) {
277 const char *no;
278 const char *from = "";
279 const char *domain = "";
280 struct domain_initializer_entry *ptr;
281 ptr = list1_entry(pos, struct domain_initializer_entry, list);
282 if (ptr->is_deleted)
283 continue;
284 no = ptr->is_not ? "no_" : "";
285 if (ptr->domainname) {
286 from = " from ";
287 domain = ptr->domainname->name;
288 }
289 if (!ccs_io_printf(head,
290 "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",
291 no, ptr->program->name, from, domain))
292 goto out;
293 }
294 return true;
295 out:
296 return false;
297 }
298
299 /**
300 * ccs_write_domain_initializer_policy - Write "struct domain_initializer_entry" list.
301 *
302 * @data: String to parse.
303 * @is_not: True if it is "no_initialize_domain" entry.
304 * @is_delete: True if it is a delete request.
305 *
306 * Returns 0 on success, negative value otherwise.
307 */
308 int ccs_write_domain_initializer_policy(char *data, const bool is_not,
309 const bool is_delete)
310 {
311 char *cp = strstr(data, " from ");
312 if (cp) {
313 *cp = '\0';
314 return update_domain_initializer_entry(cp + 6, data, is_not,
315 is_delete);
316 }
317 return update_domain_initializer_entry(NULL, data, is_not, is_delete);
318 }
319
320 /**
321 * is_domain_initializer - Check whether the given program causes domainname reinitialization.
322 *
323 * @domainname: The name of domain.
324 * @program: The name of program.
325 * @last_name: The last component of @domainname.
326 *
327 * Returns true if executing @program reinitializes domain transition,
328 * false otherwise.
329 */
330 static bool is_domain_initializer(const struct path_info *domainname,
331 const struct path_info *program,
332 const struct path_info *last_name)
333 {
334 struct domain_initializer_entry *ptr;
335 bool flag = false;
336 list1_for_each_entry(ptr, &domain_initializer_list, list) {
337 if (ptr->is_deleted)
338 continue;
339 if (ptr->domainname) {
340 if (!ptr->is_last_name) {
341 if (ptr->domainname != domainname)
342 continue;
343 } else {
344 if (ccs_pathcmp(ptr->domainname, last_name))
345 continue;
346 }
347 }
348 if (ccs_pathcmp(ptr->program, program))
349 continue;
350 if (ptr->is_not)
351 return false;
352 flag = true;
353 }
354 return flag;
355 }
356
357 /* The list for "struct domain_keeper_entry". */
358 static LIST1_HEAD(domain_keeper_list);
359
360 /**
361 * update_domain_keeper_entry - Update "struct domain_keeper_entry" list.
362 *
363 * @domainname: The name of domain.
364 * @program: The name of program. May be NULL.
365 * @is_not: True if it is "no_keep_domain" entry.
366 * @is_delete: True if it is a delete request.
367 *
368 * Returns 0 on success, negative value otherwise.
369 */
370 static int update_domain_keeper_entry(const char *domainname,
371 const char *program,
372 const bool is_not, const bool is_delete)
373 {
374 struct domain_keeper_entry *new_entry;
375 struct domain_keeper_entry *ptr;
376 const struct path_info *saved_domainname;
377 const struct path_info *saved_program = NULL;
378 static DEFINE_MUTEX(lock);
379 int error = -ENOMEM;
380 bool is_last_name = false;
381 if (!ccs_is_domain_def(domainname) &&
382 ccs_is_correct_path(domainname, 1, -1, -1, __func__))
383 is_last_name = true;
384 else if (!ccs_is_correct_domain(domainname, __func__))
385 return -EINVAL;
386 if (program) {
387 if (!ccs_is_correct_path(program, 1, -1, -1, __func__))
388 return -EINVAL;
389 saved_program = ccs_save_name(program);
390 if (!saved_program)
391 return -ENOMEM;
392 }
393 saved_domainname = ccs_save_name(domainname);
394 if (!saved_domainname)
395 return -ENOMEM;
396 mutex_lock(&lock);
397 list1_for_each_entry(ptr, &domain_keeper_list, list) {
398 if (ptr->is_not != is_not ||
399 ptr->domainname != saved_domainname ||
400 ptr->program != saved_program)
401 continue;
402 ptr->is_deleted = is_delete;
403 error = 0;
404 goto out;
405 }
406 if (is_delete) {
407 error = -ENOENT;
408 goto out;
409 }
410 new_entry = ccs_alloc_element(sizeof(*new_entry));
411 if (!new_entry)
412 goto out;
413 new_entry->domainname = saved_domainname;
414 new_entry->program = saved_program;
415 new_entry->is_not = is_not;
416 new_entry->is_last_name = is_last_name;
417 list1_add_tail_mb(&new_entry->list, &domain_keeper_list);
418 error = 0;
419 out:
420 mutex_unlock(&lock);
421 ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
422 return error;
423 }
424
425 /**
426 * ccs_write_domain_keeper_policy - Write "struct domain_keeper_entry" list.
427 *
428 * @data: String to parse.
429 * @is_not: True if it is "no_keep_domain" entry.
430 * @is_delete: True if it is a delete request.
431 *
432 */
433 int ccs_write_domain_keeper_policy(char *data, const bool is_not,
434 const bool is_delete)
435 {
436 char *cp = strstr(data, " from ");
437 if (cp) {
438 *cp = '\0';
439 return update_domain_keeper_entry(cp + 6, data,
440 is_not, is_delete);
441 }
442 return update_domain_keeper_entry(data, NULL, is_not, is_delete);
443 }
444
445 /**
446 * ccs_read_domain_keeper_policy - Read "struct domain_keeper_entry" list.
447 *
448 * @head: Pointer to "struct ccs_io_buffer".
449 *
450 * Returns true on success, false otherwise.
451 */
452 bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
453 {
454 struct list1_head *pos;
455 list1_for_each_cookie(pos, head->read_var2, &domain_keeper_list) {
456 struct domain_keeper_entry *ptr;
457 const char *no;
458 const char *from = "";
459 const char *program = "";
460 ptr = list1_entry(pos, struct domain_keeper_entry, list);
461 if (ptr->is_deleted)
462 continue;
463 no = ptr->is_not ? "no_" : "";
464 if (ptr->program) {
465 from = " from ";
466 program = ptr->program->name;
467 }
468 if (!ccs_io_printf(head,
469 "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,
470 program, from, ptr->domainname->name))
471 goto out;
472 }
473 return true;
474 out:
475 return false;
476 }
477
478 /**
479 * is_domain_keeper - Check whether the given program causes domain transition suppression.
480 *
481 * @domainname: The name of domain.
482 * @program: The name of program.
483 * @last_name: The last component of @domainname.
484 *
485 * Returns true if executing @program supresses domain transition,
486 * false otherwise.
487 */
488 static bool is_domain_keeper(const struct path_info *domainname,
489 const struct path_info *program,
490 const struct path_info *last_name)
491 {
492 struct domain_keeper_entry *ptr;
493 bool flag = false;
494 list1_for_each_entry(ptr, &domain_keeper_list, list) {
495 if (ptr->is_deleted)
496 continue;
497 if (!ptr->is_last_name) {
498 if (ptr->domainname != domainname)
499 continue;
500 } else {
501 if (ccs_pathcmp(ptr->domainname, last_name))
502 continue;
503 }
504 if (ptr->program && ccs_pathcmp(ptr->program, program))
505 continue;
506 if (ptr->is_not)
507 return false;
508 flag = true;
509 }
510 return flag;
511 }
512
513 /* The list for "struct alias_entry". */
514 static LIST1_HEAD(alias_list);
515
516 /**
517 * update_alias_entry - Update "struct alias_entry" list.
518 *
519 * @original_name: The original program's real name.
520 * @aliased_name: The symbolic program's symbolic link's name.
521 * @is_delete: True if it is a delete request.
522 *
523 * Returns 0 on success, negative value otherwise.
524 */
525 static int update_alias_entry(const char *original_name,
526 const char *aliased_name,
527 const bool is_delete)
528 {
529 struct alias_entry *new_entry;
530 struct alias_entry *ptr;
531 static DEFINE_MUTEX(lock);
532 const struct path_info *saved_original_name;
533 const struct path_info *saved_aliased_name;
534 int error = -ENOMEM;
535 if (!ccs_is_correct_path(original_name, 1, -1, -1, __func__) ||
536 !ccs_is_correct_path(aliased_name, 1, -1, -1, __func__))
537 return -EINVAL; /* No patterns allowed. */
538 saved_original_name = ccs_save_name(original_name);
539 saved_aliased_name = ccs_save_name(aliased_name);
540 if (!saved_original_name || !saved_aliased_name)
541 return -ENOMEM;
542 mutex_lock(&lock);
543 list1_for_each_entry(ptr, &alias_list, list) {
544 if (ptr->original_name != saved_original_name ||
545 ptr->aliased_name != saved_aliased_name)
546 continue;
547 ptr->is_deleted = is_delete;
548 error = 0;
549 goto out;
550 }
551 if (is_delete) {
552 error = -ENOENT;
553 goto out;
554 }
555 new_entry = ccs_alloc_element(sizeof(*new_entry));
556 if (!new_entry)
557 goto out;
558 new_entry->original_name = saved_original_name;
559 new_entry->aliased_name = saved_aliased_name;
560 list1_add_tail_mb(&new_entry->list, &alias_list);
561 error = 0;
562 out:
563 mutex_unlock(&lock);
564 ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
565 return error;
566 }
567
568 /**
569 * ccs_read_alias_policy - Read "struct alias_entry" list.
570 *
571 * @head: Pointer to "struct ccs_io_buffer".
572 *
573 * Returns true on success, false otherwise.
574 */
575 bool ccs_read_alias_policy(struct ccs_io_buffer *head)
576 {
577 struct list1_head *pos;
578 list1_for_each_cookie(pos, head->read_var2, &alias_list) {
579 struct alias_entry *ptr;
580 ptr = list1_entry(pos, struct alias_entry, list);
581 if (ptr->is_deleted)
582 continue;
583 if (!ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",
584 ptr->original_name->name,
585 ptr->aliased_name->name))
586 goto out;
587 }
588 return true;
589 out:
590 return false;
591 }
592
593 /**
594 * ccs_write_alias_policy - Write "struct alias_entry" list.
595 *
596 * @data: String to parse.
597 * @is_delete: True if it is a delete request.
598 *
599 * Returns 0 on success, negative value otherwise.
600 */
601 int ccs_write_alias_policy(char *data, const bool is_delete)
602 {
603 char *cp = strchr(data, ' ');
604 if (!cp)
605 return -EINVAL;
606 *cp++ = '\0';
607 return update_alias_entry(data, cp, is_delete);
608 }
609
610 /* The list for "struct aggregator_entry". */
611 static LIST1_HEAD(aggregator_list);
612
613 /**
614 * update_aggregator_entry - Update "struct aggregator_entry" list.
615 *
616 * @original_name: The original program's name.
617 * @aggregated_name: The aggregated program's name.
618 * @is_delete: True if it is a delete request.
619 *
620 * Returns 0 on success, negative value otherwise.
621 */
622 static int update_aggregator_entry(const char *original_name,
623 const char *aggregated_name,
624 const bool is_delete)
625 {
626 struct aggregator_entry *new_entry;
627 struct aggregator_entry *ptr;
628 static DEFINE_MUTEX(lock);
629 const struct path_info *saved_original_name;
630 const struct path_info *saved_aggregated_name;
631 int error = -ENOMEM;
632 if (!ccs_is_correct_path(original_name, 1, 0, -1, __func__) ||
633 !ccs_is_correct_path(aggregated_name, 1, -1, -1, __func__))
634 return -EINVAL;
635 saved_original_name = ccs_save_name(original_name);
636 saved_aggregated_name = ccs_save_name(aggregated_name);
637 if (!saved_original_name || !saved_aggregated_name)
638 return -ENOMEM;
639 mutex_lock(&lock);
640 list1_for_each_entry(ptr, &aggregator_list, list) {
641 if (ptr->original_name != saved_original_name ||
642 ptr->aggregated_name != saved_aggregated_name)
643 continue;
644 ptr->is_deleted = is_delete;
645 error = 0;
646 goto out;
647 }
648 if (is_delete) {
649 error = -ENOENT;
650 goto out;
651 }
652 new_entry = ccs_alloc_element(sizeof(*new_entry));
653 if (!new_entry)
654 goto out;
655 new_entry->original_name = saved_original_name;
656 new_entry->aggregated_name = saved_aggregated_name;
657 list1_add_tail_mb(&new_entry->list, &aggregator_list);
658 error = 0;
659 out:
660 mutex_unlock(&lock);
661 ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
662 return error;
663 }
664
665 /**
666 * ccs_read_aggregator_policy - Read "struct aggregator_entry" list.
667 *
668 * @head: Pointer to "struct ccs_io_buffer".
669 *
670 * Returns true on success, false otherwise.
671 */
672 bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
673 {
674 struct list1_head *pos;
675 list1_for_each_cookie(pos, head->read_var2, &aggregator_list) {
676 struct aggregator_entry *ptr;
677 ptr = list1_entry(pos, struct aggregator_entry, list);
678 if (ptr->is_deleted)
679 continue;
680 if (!ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",
681 ptr->original_name->name,
682 ptr->aggregated_name->name))
683 goto out;
684 }
685 return true;
686 out:
687 return false;
688 }
689
690 /**
691 * ccs_write_aggregator_policy - Write "struct aggregator_entry" list.
692 *
693 * @data: String to parse.
694 * @is_delete: True if it is a delete request.
695 *
696 * Returns 0 on success, negative value otherwise.
697 */
698 int ccs_write_aggregator_policy(char *data, const bool is_delete)
699 {
700 char *cp = strchr(data, ' ');
701 if (!cp)
702 return -EINVAL;
703 *cp++ = '\0';
704 return update_aggregator_entry(data, cp, is_delete);
705 }
706
707 /* Domain create/delete/undelete handler. */
708
709 /* #define DEBUG_DOMAIN_UNDELETE */
710
711 /**
712 * ccs_delete_domain - Delete a domain.
713 *
714 * @domainname: The name of domain.
715 *
716 * Returns 0.
717 */
718 int ccs_delete_domain(char *domainname)
719 {
720 struct domain_info *domain;
721 struct path_info name;
722 name.name = domainname;
723 ccs_fill_path_info(&name);
724 mutex_lock(&domain_list_lock);
725 #ifdef DEBUG_DOMAIN_UNDELETE
726 printk(KERN_DEBUG "ccs_delete_domain %s\n", domainname);
727 list1_for_each_entry(domain, &domain_list, list) {
728 if (ccs_pathcmp(domain->domainname, &name))
729 continue;
730 printk(KERN_DEBUG "List: %p %u\n", domain, domain->is_deleted);
731 }
732 #endif
733 /* Is there an active domain? */
734 list1_for_each_entry(domain, &domain_list, list) {
735 struct domain_info *domain2;
736 /* Never delete KERNEL_DOMAIN */
737 if (domain == &KERNEL_DOMAIN)
738 continue;
739 if (domain->is_deleted ||
740 ccs_pathcmp(domain->domainname, &name))
741 continue;
742 /* Mark already deleted domains as non undeletable. */
743 list1_for_each_entry(domain2, &domain_list, list) {
744 if (!domain2->is_deleted ||
745 ccs_pathcmp(domain2->domainname, &name))
746 continue;
747 #ifdef DEBUG_DOMAIN_UNDELETE
748 if (domain2->is_deleted != 255)
749 printk(KERN_DEBUG
750 "Marked %p as non undeletable\n",
751 domain2);
752 #endif
753 domain2->is_deleted = 255;
754 }
755 /* Delete and mark active domain as undeletable. */
756 domain->is_deleted = 1;
757 #ifdef DEBUG_DOMAIN_UNDELETE
758 printk(KERN_DEBUG "Marked %p as undeletable\n", domain);
759 #endif
760 break;
761 }
762 mutex_unlock(&domain_list_lock);
763 return 0;
764 }
765
766 /**
767 * ccs_undelete_domain - Undelete a domain.
768 *
769 * @domainname: The name of domain.
770 *
771 * Returns pointer to "struct domain_info" on success, NULL otherwise.
772 */
773 struct domain_info *ccs_undelete_domain(const char *domainname)
774 {
775 struct domain_info *domain;
776 struct domain_info *candidate_domain = NULL;
777 struct path_info name;
778 name.name = domainname;
779 ccs_fill_path_info(&name);
780 mutex_lock(&domain_list_lock);
781 #ifdef DEBUG_DOMAIN_UNDELETE
782 printk(KERN_DEBUG "ccs_undelete_domain %s\n", domainname);
783 list1_for_each_entry(domain, &domain_list, list) {
784 if (ccs_pathcmp(domain->domainname, &name))
785 continue;
786 printk(KERN_DEBUG "List: %p %u\n", domain, domain->is_deleted);
787 }
788 #endif
789 list1_for_each_entry(domain, &domain_list, list) {
790 if (ccs_pathcmp(&name, domain->domainname))
791 continue;
792 if (!domain->is_deleted) {
793 /* This domain is active. I can't undelete. */
794 candidate_domain = NULL;
795 #ifdef DEBUG_DOMAIN_UNDELETE
796 printk(KERN_DEBUG "%p is active. I can't undelete.\n",
797 domain);
798 #endif
799 break;
800 }
801 /* Is this domain undeletable? */
802 if (domain->is_deleted == 1)
803 candidate_domain = domain;
804 }
805 if (candidate_domain) {
806 candidate_domain->is_deleted = 0;
807 #ifdef DEBUG_DOMAIN_UNDELETE
808 printk(KERN_DEBUG "%p was undeleted.\n", candidate_domain);
809 #endif
810 }
811 mutex_unlock(&domain_list_lock);
812 return candidate_domain;
813 }
814
815 /**
816 * ccs_find_or_assign_new_domain - Create a domain.
817 *
818 * @domainname: The name of domain.
819 * @profile: Profile number to assign if the domain was newly created.
820 *
821 * Returns pointer to "struct domain_info" on success, NULL otherwise.
822 */
823 struct domain_info *ccs_find_or_assign_new_domain(const char *domainname,
824 const u8 profile)
825 {
826 struct domain_info *domain = NULL;
827 const struct path_info *saved_domainname;
828 mutex_lock(&domain_list_lock);
829 domain = ccs_find_domain(domainname);
830 if (domain)
831 goto out;
832 if (!ccs_is_correct_domain(domainname, __func__))
833 goto out;
834 saved_domainname = ccs_save_name(domainname);
835 if (!saved_domainname)
836 goto out;
837 /* Can I reuse memory of deleted domain? */
838 list1_for_each_entry(domain, &domain_list, list) {
839 struct task_struct *p;
840 struct acl_info *ptr;
841 bool flag;
842 if (!domain->is_deleted ||
843 domain->domainname != saved_domainname)
844 continue;
845 flag = false;
846 /***** CRITICAL SECTION START *****/
847 read_lock(&tasklist_lock);
848 for_each_process(p) {
849 if (p->domain_info != domain)
850 continue;
851 flag = true;
852 break;
853 }
854 read_unlock(&tasklist_lock);
855 /***** CRITICAL SECTION END *****/
856 if (flag)
857 continue;
858 #ifdef DEBUG_DOMAIN_UNDELETE
859 printk(KERN_DEBUG "Reusing %p %s\n", domain,
860 domain->domainname->name);
861 #endif
862 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
863 ptr->type |= ACL_DELETED;
864 }
865 ccs_set_domain_flag(domain, true, domain->flags);
866 domain->profile = profile;
867 domain->quota_warned = false;
868 mb(); /* Avoid out-of-order execution. */
869 domain->is_deleted = 0;
870 goto out;
871 }
872 /* No memory reusable. Create using new memory. */
873 domain = ccs_alloc_element(sizeof(*domain));
874 if (domain) {
875 INIT_LIST1_HEAD(&domain->acl_info_list);
876 domain->domainname = saved_domainname;
877 domain->profile = profile;
878 list1_add_tail_mb(&domain->list, &domain_list);
879 }
880 out:
881 mutex_unlock(&domain_list_lock);
882 return domain;
883 }
884
885 /**
886 * get_argv0 - Get argv[0].
887 *
888 * @bprm: Pointer to "struct linux_binprm".
889 * @tmp: Buffer for temporal use.
890 *
891 * Returns true on success, false otherwise.
892 */
893 static bool get_argv0(struct linux_binprm *bprm, struct ccs_page_buffer *tmp)
894 {
895 char *arg_ptr = tmp->buffer;
896 int arg_len = 0;
897 unsigned long pos = bprm->p;
898 int i = pos / PAGE_SIZE;
899 int offset = pos % PAGE_SIZE;
900 bool done = false;
901 if (!bprm->argc)
902 goto out;
903 while (1) {
904 struct page *page;
905 const char *kaddr;
906 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
907 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page,
908 NULL) <= 0)
909 goto out;
910 pos += PAGE_SIZE - offset;
911 #else
912 page = bprm->page[i];
913 #endif
914 /* Map. */
915 kaddr = kmap(page);
916 if (!kaddr) { /* Mapping failed. */
917 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
918 put_page(page);
919 #endif
920 goto out;
921 }
922 /* Read. */
923 while (offset < PAGE_SIZE) {
924 const unsigned char c = kaddr[offset++];
925 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
926 if (c == '\\') {
927 arg_ptr[arg_len++] = '\\';
928 arg_ptr[arg_len++] = '\\';
929 } else if (c == '/') {
930 arg_len = 0;
931 } else if (c > ' ' && c < 127) {
932 arg_ptr[arg_len++] = c;
933 } else {
934 arg_ptr[arg_len++] = '\\';
935 arg_ptr[arg_len++] = (c >> 6) + '0';
936 arg_ptr[arg_len++]
937 = ((c >> 3) & 7) + '0';
938 arg_ptr[arg_len++] = (c & 7) + '0';
939 }
940 } else {
941 arg_ptr[arg_len] = '\0';
942 done = true;
943 break;
944 }
945 }
946 /* Unmap. */
947 kunmap(page);
948 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
949 put_page(page);
950 #endif
951 i++;
952 offset = 0;
953 if (done)
954 break;
955 }
956 return true;
957 out:
958 return false;
959 }
960
961 /**
962 * find_next_domain - Find a domain.
963 *
964 * @r: Pointer to "struct ccs_request_info".
965 * @handler: Pathname to verify. May be NULL.
966 *
967 * Returns 0 on success, negative value otherwise.
968 */
969 static int find_next_domain(struct ccs_request_info *r,
970 const struct path_info *handler)
971 {
972 /*
973 * This function assumes that the size of buffer returned by
974 * ccs_realpath() = CCS_MAX_PATHNAME_LEN.
975 */
976 struct domain_info *domain = NULL;
977 const char *old_domain_name = r->domain->domainname->name;
978 struct linux_binprm *bprm = r->bprm;
979 struct ccs_page_buffer *tmp = r->obj->tmp;
980 const char *original_name = bprm->filename;
981 const u8 mode = r->mode;
982 const bool is_enforce = (mode == 3);
983 const u32 tomoyo_flags = r->tomoyo_flags;
984 char *new_domain_name = NULL;
985 char *real_program_name = NULL;
986 char *symlink_program_name = NULL;
987 struct path_info rn; /* real name */
988 struct path_info sn; /* symlink name */
989 struct path_info ln; /* last name */
990 int retval;
991
992 {
993 /*
994 * Built-in initializers. This is needed because policies are
995 * not loaded until starting /sbin/init.
996 */
997 static bool first = true;
998 if (first) {
999 update_domain_initializer_entry(NULL, "/sbin/hotplug",
1000 false, false);
1001 update_domain_initializer_entry(NULL, "/sbin/modprobe",
1002 false, false);
1003 first = false;
1004 }
1005 }
1006
1007 retry:
1008 current->tomoyo_flags = tomoyo_flags;
1009 r->tomoyo_flags = tomoyo_flags;
1010 /* Get ccs_realpath of program. */
1011 retval = -ENOENT; /* I hope ccs_realpath() won't fail with -ENOMEM. */
1012 ccs_free(real_program_name);
1013 real_program_name = ccs_realpath(original_name);
1014 if (!real_program_name)
1015 goto out;
1016 /* Get ccs_realpath of symbolic link. */
1017 ccs_free(symlink_program_name);
1018 symlink_program_name = ccs_realpath_nofollow(original_name);
1019 if (!symlink_program_name)
1020 goto out;
1021
1022 rn.name = real_program_name;
1023 ccs_fill_path_info(&rn);
1024 sn.name = symlink_program_name;
1025 ccs_fill_path_info(&sn);
1026 ln.name = ccs_get_last_name(r->domain);
1027 ccs_fill_path_info(&ln);
1028
1029 if (handler) {
1030 if (ccs_pathcmp(&rn, handler)) {
1031 /* Failed to verify execute handler. */
1032 static u8 counter = 20;
1033 if (counter) {
1034 counter--;
1035 printk(KERN_WARNING "Failed to verify: %s\n",
1036 handler->name);
1037 }
1038 goto out;
1039 }
1040 goto calculate_domain;
1041 }
1042
1043 /* Check 'alias' directive. */
1044 if (ccs_pathcmp(&rn, &sn)) {
1045 struct alias_entry *ptr;
1046 /* Is this program allowed to be called via symbolic links? */
1047 list1_for_each_entry(ptr, &alias_list, list) {
1048 if (ptr->is_deleted ||
1049 ccs_pathcmp(&rn, ptr->original_name) ||
1050 ccs_pathcmp(&sn, ptr->aliased_name))
1051 continue;
1052 memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);
1053 strncpy(real_program_name, ptr->aliased_name->name,
1054 CCS_MAX_PATHNAME_LEN - 1);
1055 ccs_fill_path_info(&rn);
1056 break;
1057 }
1058 }
1059
1060 /* Compare basename of real_program_name and argv[0] */
1061 r->mode = ccs_check_flags(r->domain, CCS_TOMOYO_MAC_FOR_ARGV0);
1062 if (bprm->argc > 0 && r->mode) {
1063 char *base_argv0 = tmp->buffer;
1064 const char *base_filename;
1065 retval = -ENOMEM;
1066 if (!get_argv0(bprm, tmp))
1067 goto out;
1068 base_filename = strrchr(real_program_name, '/');
1069 if (!base_filename)
1070 base_filename = real_program_name;
1071 else
1072 base_filename++;
1073 if (strcmp(base_argv0, base_filename)) {
1074 retval = ccs_check_argv0_perm(r, &rn, base_argv0);
1075 if (retval == 1) {
1076 r->retry++;
1077 goto retry;
1078 }
1079 r->retry = 0;
1080 if (retval < 0)
1081 goto out;
1082 }
1083 }
1084
1085 /* Check 'aggregator' directive. */
1086 {
1087 struct aggregator_entry *ptr;
1088 /* Is this program allowed to be aggregated? */
1089 list1_for_each_entry(ptr, &aggregator_list, list) {
1090 if (ptr->is_deleted ||
1091 !ccs_path_matches_pattern(&rn, ptr->original_name))
1092 continue;
1093 memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);
1094 strncpy(real_program_name, ptr->aggregated_name->name,
1095 CCS_MAX_PATHNAME_LEN - 1);
1096 ccs_fill_path_info(&rn);
1097 break;
1098 }
1099 }
1100
1101 /* Check execute permission. */
1102 r->mode = mode;
1103 retval = ccs_check_exec_perm(r, &rn);
1104 if (retval == 1) {
1105 r->retry++;
1106 goto retry;
1107 }
1108 r->retry = 0;
1109 if (retval < 0)
1110 goto out;
1111
1112 calculate_domain:
1113 new_domain_name = tmp->buffer;
1114 if (is_domain_initializer(r->domain->domainname, &rn, &ln)) {
1115 /* Transit to the child of KERNEL_DOMAIN domain. */
1116 snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,
1117 ROOT_NAME " " "%s", real_program_name);
1118 } else if (r->domain == &KERNEL_DOMAIN && !sbin_init_started) {
1119 /*
1120 * Needn't to transit from kernel domain before starting
1121 * /sbin/init. But transit from kernel domain if executing
1122 * initializers because they might start before /sbin/init.
1123 */
1124 domain = r->domain;
1125 } else if (is_domain_keeper(r->domain->domainname, &rn, &ln)) {
1126 /* Keep current domain. */
1127 domain = r->domain;
1128 } else {
1129 /* Normal domain transition. */
1130 snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,
1131 "%s %s", old_domain_name, real_program_name);
1132 }
1133 if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
1134 goto done;
1135 domain = ccs_find_domain(new_domain_name);
1136 if (domain)
1137 goto done;
1138 if (is_enforce) {
1139 int error = ccs_check_supervisor(r,
1140 "# wants to create domain\n"
1141 "%s\n", new_domain_name);
1142 if (error == 1) {
1143 r->retry++;
1144 goto retry;
1145 }
1146 r->retry = 0;
1147 if (error < 0)
1148 goto done;
1149 }
1150 domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);
1151 if (domain)
1152 audit_domain_creation_log(domain);
1153 done:
1154 if (!domain) {
1155 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
1156 new_domain_name);
1157 if (is_enforce)
1158 retval = -EPERM;
1159 else {
1160 retval = 0;
1161 ccs_set_domain_flag(r->domain, false,
1162 DOMAIN_FLAGS_TRANSITION_FAILED);
1163 }
1164 } else {
1165 retval = 0;
1166 }
1167 out:
1168 ccs_free(real_program_name);
1169 ccs_free(symlink_program_name);
1170 if (domain)
1171 r->domain = domain;
1172 return retval;
1173 }
1174
1175 /**
1176 * check_environ - Check permission for environment variable names.
1177 *
1178 * @r: Pointer to "struct ccs_request_info".
1179 *
1180 * Returns 0 on success, negative value otherwise.
1181 */
1182 static int check_environ(struct ccs_request_info *r)
1183 {
1184 struct linux_binprm *bprm = r->bprm;
1185 struct ccs_page_buffer *tmp = r->obj->tmp;
1186 char *arg_ptr = tmp->buffer;
1187 int arg_len = 0;
1188 unsigned long pos = bprm->p;
1189 int i = pos / PAGE_SIZE;
1190 int offset = pos % PAGE_SIZE;
1191 int argv_count = bprm->argc;
1192 int envp_count = bprm->envc;
1193 /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
1194 int error = -ENOMEM;
1195 if (!r->mode || !envp_count)
1196 return 0;
1197 while (error == -ENOMEM) {
1198 struct page *page;
1199 const char *kaddr;
1200 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1201 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page,
1202 NULL) <= 0)
1203 goto out;
1204 pos += PAGE_SIZE - offset;
1205 #else
1206 page = bprm->page[i];
1207 #endif
1208 /* Map. */
1209 kaddr = kmap(page);
1210 if (!kaddr) { /* Mapping failed. */
1211 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1212 put_page(page);
1213 #endif
1214 goto out;
1215 }
1216 /* Read. */
1217 while (argv_count && offset < PAGE_SIZE) {
1218 if (!kaddr[offset++])
1219 argv_count--;
1220 }
1221 if (argv_count)
1222 goto unmap_page;
1223 while (offset < PAGE_SIZE) {
1224 const unsigned char c = kaddr[offset++];
1225 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1226 if (c == '=') {
1227 arg_ptr[arg_len++] = '\0';
1228 } else if (c == '\\') {
1229 arg_ptr[arg_len++] = '\\';
1230 arg_ptr[arg_len++] = '\\';
1231 } else if (c > ' ' && c < 127) {
1232 arg_ptr[arg_len++] = c;
1233 } else {
1234 arg_ptr[arg_len++] = '\\';
1235 arg_ptr[arg_len++] = (c >> 6) + '0';
1236 arg_ptr[arg_len++]
1237 = ((c >> 3) & 7) + '0';
1238 arg_ptr[arg_len++] = (c & 7) + '0';
1239 }
1240 } else {
1241 arg_ptr[arg_len] = '\0';
1242 }
1243 if (c)
1244 continue;
1245 if (ccs_check_env_perm(r, arg_ptr)) {
1246 error = -EPERM;
1247 break;
1248 }
1249 if (!--envp_count) {
1250 error = 0;
1251 break;
1252 }
1253 arg_len = 0;
1254 }
1255 unmap_page:
1256 /* Unmap. */
1257 kunmap(page);
1258 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1259 put_page(page);
1260 #endif
1261 i++;
1262 offset = 0;
1263 }
1264 out:
1265 if (r->mode != 3)
1266 error = 0;
1267 return error;
1268 }
1269
1270 /**
1271 * unescape - Unescape escaped string.
1272 *
1273 * @dest: String to unescape.
1274 *
1275 * Returns nothing.
1276 */
1277 static void unescape(unsigned char *dest)
1278 {
1279 unsigned char *src = dest;
1280 unsigned char c;
1281 unsigned char d;
1282 unsigned char e;
1283 while (1) {
1284 c = *src++;
1285 if (!c)
1286 break;
1287 if (c != '\\') {
1288 *dest++ = c;
1289 continue;
1290 }
1291 c = *src++;
1292 if (c == '\\') {
1293 *dest++ = c;
1294 continue;
1295 }
1296 if (c < '0' || c > '3')
1297 break;
1298 d = *src++;
1299 if (d < '0' || d > '7')
1300 break;
1301 e = *src++;
1302 if (e < '0' || e > '7')
1303 break;
1304 *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1305 }
1306 *dest = '\0';
1307 }
1308
1309 /**
1310 * root_depth - Get number of directories to strip.
1311 *
1312 * @dentry: Pointer to "struct dentry".
1313 * @vfsmnt: Pointer to "struct vfsmount".
1314 *
1315 * Returns number of directories to strip.
1316 */
1317 static inline int root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1318 {
1319 int depth = 0;
1320 /***** CRITICAL SECTION START *****/
1321 ccs_realpath_lock();
1322 for (;;) {
1323 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1324 /* Global root? */
1325 if (vfsmnt->mnt_parent == vfsmnt)
1326 break;
1327 dentry = vfsmnt->mnt_mountpoint;
1328 vfsmnt = vfsmnt->mnt_parent;
1329 continue;
1330 }
1331 dentry = dentry->d_parent;
1332 depth++;
1333 }
1334 ccs_realpath_unlock();
1335 /***** CRITICAL SECTION END *****/
1336 return depth;
1337 }
1338
1339 /**
1340 * get_root_depth - return the depth of root directory.
1341 *
1342 * Returns number of directories to strip.
1343 */
1344 static int get_root_depth(void)
1345 {
1346 int depth;
1347 struct dentry *dentry;
1348 struct vfsmount *vfsmnt;
1349 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1350 struct path root;
1351 #endif
1352 /***** CRITICAL SECTION START *****/
1353 read_lock(&current->fs->lock);
1354 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1355 root = current->fs->root;
1356 path_get(&current->fs->root);
1357 dentry = root.dentry;
1358 vfsmnt = root.mnt;
1359 #else
1360 dentry = dget(current->fs->root);
1361 vfsmnt = mntget(current->fs->rootmnt);
1362 #endif
1363 read_unlock(&current->fs->lock);
1364 /***** CRITICAL SECTION END *****/
1365 depth = root_depth(dentry, vfsmnt);
1366 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1367 path_put(&root);
1368 #else
1369 dput(dentry);
1370 mntput(vfsmnt);
1371 #endif
1372 return depth;
1373 }
1374
1375 /**
1376 * try_alt_exec - Try to start execute handler.
1377 *
1378 * @r: Pointer to "struct ccs_request_info".
1379 * @handler: Pointer to the name of execute handler.
1380 * @eh_path: Pointer to pointer to the name of execute handler.
1381 *
1382 * Returns 0 on success, negative value otherwise.
1383 */
1384 static int try_alt_exec(struct ccs_request_info *r,
1385 const struct path_info *handler, char **eh_path)
1386 {
1387 /*
1388 * Contents of modified bprm.
1389 * The envp[] in original bprm is moved to argv[] so that
1390 * the alternatively executed program won't be affected by
1391 * some dangerous environment variables like LD_PRELOAD.
1392 *
1393 * modified bprm->argc
1394 * = original bprm->argc + original bprm->envc + 7
1395 * modified bprm->envc
1396 * = 0
1397 *
1398 * modified bprm->argv[0]
1399 * = the program's name specified by execute_handler
1400 * modified bprm->argv[1]
1401 * = current->domain_info->domainname->name
1402 * modified bprm->argv[2]
1403 * = the current process's name
1404 * modified bprm->argv[3]
1405 * = the current process's information (e.g. uid/gid).
1406 * modified bprm->argv[4]
1407 * = original bprm->filename
1408 * modified bprm->argv[5]
1409 * = original bprm->argc in string expression
1410 * modified bprm->argv[6]
1411 * = original bprm->envc in string expression
1412 * modified bprm->argv[7]
1413 * = original bprm->argv[0]
1414 * ...
1415 * modified bprm->argv[bprm->argc + 6]
1416 * = original bprm->argv[bprm->argc - 1]
1417 * modified bprm->argv[bprm->argc + 7]
1418 * = original bprm->envp[0]
1419 * ...
1420 * modified bprm->argv[bprm->envc + bprm->argc + 6]
1421 * = original bprm->envp[bprm->envc - 1]
1422 */
1423 struct linux_binprm *bprm = r->bprm;
1424 struct file *filp;
1425 int retval;
1426 const int original_argc = bprm->argc;
1427 const int original_envc = bprm->envc;
1428 struct task_struct *task = current;
1429 char *buffer = r->obj->tmp->buffer;
1430 /* Allocate memory for execute handler's pathname. */
1431 char *execute_handler = ccs_alloc(sizeof(struct ccs_page_buffer));
1432 *eh_path = execute_handler;
1433 if (!execute_handler)
1434 return -ENOMEM;
1435 strncpy(execute_handler, handler->name,
1436 sizeof(struct ccs_page_buffer) - 1);
1437 unescape(execute_handler);
1438
1439 /* Close the requested program's dentry. */
1440 allow_write_access(bprm->file);
1441 fput(bprm->file);
1442 bprm->file = NULL;
1443
1444 { /* Adjust root directory for open_exec(). */
1445 int depth = get_root_depth();
1446 char *cp = execute_handler;
1447 if (!*cp || *cp != '/')
1448 return -ENOENT;
1449 while (depth) {
1450 cp = strchr(cp + 1, '/');
1451 if (!cp)
1452 return -ENOENT;
1453 depth--;
1454 }
1455 memmove(execute_handler, cp, strlen(cp) + 1);
1456 }
1457
1458 /* Move envp[] to argv[] */
1459 bprm->argc += bprm->envc;
1460 bprm->envc = 0;
1461
1462 /* Set argv[6] */
1463 {
1464 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1465 original_envc);
1466 retval = copy_strings_kernel(1, &buffer, bprm);
1467 if (retval < 0)
1468 goto out;
1469 bprm->argc++;
1470 }
1471
1472 /* Set argv[5] */
1473 {
1474 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1475 original_argc);
1476 retval = copy_strings_kernel(1, &buffer, bprm);
1477 if (retval < 0)
1478 goto out;
1479 bprm->argc++;
1480 }
1481
1482 /* Set argv[4] */
1483 {
1484 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1485 if (retval < 0)
1486 goto out;
1487 bprm->argc++;
1488 }
1489
1490 /* Set argv[3] */
1491 {
1492 const u32 tomoyo_flags = task->tomoyo_flags;
1493 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1494 "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1495 "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1496 "state[1]=%u state[2]=%u",
1497 task->pid, task->uid, task->gid, task->euid,
1498 task->egid, task->suid, task->sgid, task->fsuid,
1499 task->fsgid, (u8) (tomoyo_flags >> 24),
1500 (u8) (tomoyo_flags >> 16), (u8) (tomoyo_flags >> 8));
1501 retval = copy_strings_kernel(1, &buffer, bprm);
1502 if (retval < 0)
1503 goto out;
1504 bprm->argc++;
1505 }
1506
1507 /* Set argv[2] */
1508 {
1509 char *exe = (char *) ccs_get_exe();
1510 if (exe) {
1511 retval = copy_strings_kernel(1, &exe, bprm);
1512 ccs_free(exe);
1513 } else {
1514 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1515 "<unknown>");
1516 retval = copy_strings_kernel(1, &buffer, bprm);
1517 }
1518 if (retval < 0)
1519 goto out;
1520 bprm->argc++;
1521 }
1522
1523 /* Set argv[1] */
1524 {
1525 strncpy(buffer, task->domain_info->domainname->name,
1526 sizeof(struct ccs_page_buffer) - 1);
1527 retval = copy_strings_kernel(1, &buffer, bprm);
1528 if (retval < 0)
1529 goto out;
1530 bprm->argc++;
1531 }
1532
1533 /* Set argv[0] */
1534 {
1535 retval = copy_strings_kernel(1, &execute_handler, bprm);
1536 if (retval < 0)
1537 goto out;
1538 bprm->argc++;
1539 }
1540 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1541 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1542 bprm->argv_len = bprm->exec - bprm->p;
1543 #endif
1544 #endif
1545
1546 /* OK, now restart the process with execute handler program's dentry. */
1547 filp = open_exec(execute_handler);
1548 if (IS_ERR(filp)) {
1549 retval = PTR_ERR(filp);
1550 goto out;
1551 }
1552 bprm->file = filp;
1553 bprm->filename = execute_handler;
1554 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1555 bprm->interp = execute_handler;
1556 #endif
1557 retval = prepare_binprm(bprm);
1558 if (retval < 0)
1559 goto out;
1560 task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1561 retval = find_next_domain(r, handler);
1562 task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1563 out:
1564 return retval;
1565 }
1566
1567 /**
1568 * find_execute_handler - Find an execute handler.
1569 *
1570 * @type: Type of execute handler.
1571 *
1572 * Returns pointer to "struct path_info" if found, NULL otherwise.
1573 */
1574 static const struct path_info *find_execute_handler(const u8 type)
1575 {
1576 struct task_struct *task = current;
1577 const struct domain_info *domain = task->domain_info;
1578 struct acl_info *ptr;
1579 /*
1580 * Don't use execute handler if the current process is
1581 * marked as execute handler to avoid infinite execute handler loop.
1582 */
1583 if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)
1584 return NULL;
1585 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
1586 struct execute_handler_record *acl;
1587 if (ptr->type != type)
1588 continue;
1589 acl = container_of(ptr, struct execute_handler_record, head);
1590 return acl->handler;
1591 }
1592 return NULL;
1593 }
1594
1595 /* List of next_domain which is used for checking interpreter's permissions. */
1596 struct execve_entry {
1597 struct list_head list;
1598 struct task_struct *task;
1599 struct domain_info *next_domain;
1600 };
1601
1602 static LIST_HEAD(execve_list);
1603 static DEFINE_SPINLOCK(execve_list_lock);
1604
1605 /**
1606 * ccs_register_next_domain - Remember next_domain.
1607 *
1608 * @next_domain: Pointer to "struct domain_info".
1609 *
1610 * Returns 0 on success, -ENOMEM otherwise.
1611 */
1612 static int ccs_register_next_domain(struct domain_info *next_domain)
1613 {
1614 struct execve_entry *ee = kmalloc(sizeof(*ee), GFP_KERNEL);
1615 if (!ee)
1616 return -ENOMEM;
1617 ee->task = current;
1618 ee->next_domain = next_domain;
1619 /***** CRITICAL SECTION START *****/
1620 spin_lock(&execve_list_lock);
1621 list_add(&ee->list, &execve_list);
1622 spin_unlock(&execve_list_lock);
1623 /***** CRITICAL SECTION END *****/
1624 return 0;
1625 }
1626
1627 /**
1628 * ccs_fetch_next_domain - Fetch next_domain from the list.
1629 *
1630 * Returns pointer to "struct domain_info" which will be used if execve()
1631 * succeeds. This function does not return NULL.
1632 */
1633 struct domain_info *ccs_fetch_next_domain(void)
1634 {
1635 struct task_struct *task = current;
1636 struct domain_info *next_domain = task->domain_info;
1637 struct execve_entry *p;
1638 /***** CRITICAL SECTION START *****/
1639 spin_lock(&execve_list_lock);
1640 list_for_each_entry(p, &execve_list, list) {
1641 if (p->task != task)
1642 continue;
1643 next_domain = p->next_domain;
1644 break;
1645 }
1646 spin_unlock(&execve_list_lock);
1647 /***** CRITICAL SECTION END *****/
1648 return next_domain;
1649 }
1650
1651 /**
1652 * ccs_unregister_next_domain - Forget next_domain.
1653 */
1654 static void ccs_unregister_next_domain(void)
1655 {
1656 struct task_struct *task = current;
1657 struct execve_entry *p;
1658 struct execve_entry *ee = NULL;
1659 /***** CRITICAL SECTION START *****/
1660 spin_lock(&execve_list_lock);
1661 list_for_each_entry(p, &execve_list, list) {
1662 if (p->task != task)
1663 continue;
1664 list_del(&p->list);
1665 ee = p;
1666 break;
1667 }
1668 spin_unlock(&execve_list_lock);
1669 /***** CRITICAL SECTION END *****/
1670 kfree(ee);
1671 }
1672
1673 /**
1674 * search_binary_handler_with_transition - Perform domain transition.
1675 *
1676 * @bprm: Pointer to "struct linux_binprm".
1677 * @regs: Pointer to "struct pt_regs".
1678 *
1679 * Returns result of search_binary_handler() on success,
1680 * negative value otherwise.
1681 */
1682 int search_binary_handler_with_transition(struct linux_binprm *bprm,
1683 struct pt_regs *regs)
1684 {
1685 int retval;
1686 struct task_struct *task = current;
1687 const struct path_info *handler;
1688 struct ccs_request_info r;
1689 struct obj_info obj;
1690 /*
1691 * "eh_path" holds path to execute handler program.
1692 * Thus, keep valid until search_binary_handler() finishes.
1693 */
1694 char *eh_path = NULL;
1695 struct ccs_page_buffer *tmp = ccs_alloc(sizeof(struct ccs_page_buffer));
1696 memset(&obj, 0, sizeof(obj));
1697 if (!sbin_init_started)
1698 ccs_load_policy(bprm->filename);
1699 if (!tmp)
1700 return -ENOMEM;
1701
1702 ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_FILE);
1703 r.bprm = bprm;
1704 r.obj = &obj;
1705 obj.path1_dentry = bprm->file->f_dentry;
1706 obj.path1_vfsmnt = bprm->file->f_vfsmnt;
1707 obj.tmp = tmp;
1708
1709 /* Clear manager flag. */
1710 task->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1711 handler = find_execute_handler(TYPE_EXECUTE_HANDLER);
1712 if (handler) {
1713 retval = try_alt_exec(&r, handler, &eh_path);
1714 if (!retval)
1715 audit_execute_handler_log(true, handler->name, bprm);
1716 goto ok;
1717 }
1718 retval = find_next_domain(&r, NULL);
1719 if (retval != -EPERM)
1720 goto ok;
1721 handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER);
1722 if (handler) {
1723 retval = try_alt_exec(&r, handler, &eh_path);
1724 if (!retval)
1725 audit_execute_handler_log(false, handler->name, bprm);
1726 }
1727 ok:
1728 if (retval < 0)
1729 goto out;
1730 r.mode = ccs_check_flags(r.domain, CCS_TOMOYO_MAC_FOR_ENV);
1731 retval = check_environ(&r);
1732 if (retval < 0)
1733 goto out;
1734 retval = ccs_register_next_domain(r.domain);
1735 if (retval < 0)
1736 goto out;
1737 task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1738 retval = search_binary_handler(bprm, regs);
1739 task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1740 if (retval < 0)
1741 goto out;
1742 /* Proceed to next domain if execution suceeded. */
1743 task->domain_info = r.domain;
1744 mb(); /* Make domain transition visible to other CPUs. */
1745 /* Mark the current process as execute handler. */
1746 if (handler)
1747 task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;
1748 /* Mark the current process as normal process. */
1749 else
1750 task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;
1751 out:
1752 ccs_unregister_next_domain();
1753 ccs_free(eh_path);
1754 ccs_free(tmp);
1755 return retval;
1756 }
1757
1758 #else
1759
1760 /**
1761 * search_binary_handler_with_transition - Wrapper for search_binary_handler().
1762 *
1763 * @bprm: Pointer to "struct linux_binprm".
1764 * @regs: Pointer to "struct pt_regs".
1765 *
1766 * Returns the result of search_binary_handler().
1767 */
1768 int search_binary_handler_with_transition(struct linux_binprm *bprm,
1769 struct pt_regs *regs)
1770 {
1771 #ifdef CONFIG_SAKURA
1772 /* Clear manager flag. */
1773 current->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1774 ccs_load_policy(bprm->filename);
1775 #endif
1776 return search_binary_handler(bprm, regs);
1777 }
1778
1779 #endif

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26