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

Subversion リポジトリの参照

Contents of /trunk/1.6.x/ccs-patch/fs/tomoyo_domain.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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