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

Subversion リポジトリの参照

Contents of /trunk/1.8.x/ccs-patch/security/ccsecurity/domain.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1721 - (show annotations) (download) (as text)
Mon Oct 20 05:56:25 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: 46854 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 ((c = *src++) != '\0') {
1284 if (c != '\\') {
1285 *dest++ = c;
1286 continue;
1287 }
1288 c = *src++;
1289 if (c == '\\') {
1290 *dest++ = c;
1291 continue;
1292 }
1293 if (c < '0' || c > '3')
1294 break;
1295 d = *src++;
1296 if (d < '0' || d > '7')
1297 break;
1298 e = *src++;
1299 if (e < '0' || e > '7')
1300 break;
1301 *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1302 }
1303 *dest = '\0';
1304 }
1305
1306 /**
1307 * root_depth - Get number of directories to strip.
1308 *
1309 * @dentry: Pointer to "struct dentry".
1310 * @vfsmnt: Pointer to "struct vfsmount".
1311 *
1312 * Returns number of directories to strip.
1313 */
1314 static inline int root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1315 {
1316 int depth = 0;
1317 /***** CRITICAL SECTION START *****/
1318 ccs_realpath_lock();
1319 for (;;) {
1320 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1321 /* Global root? */
1322 if (vfsmnt->mnt_parent == vfsmnt)
1323 break;
1324 dentry = vfsmnt->mnt_mountpoint;
1325 vfsmnt = vfsmnt->mnt_parent;
1326 continue;
1327 }
1328 dentry = dentry->d_parent;
1329 depth++;
1330 }
1331 ccs_realpath_unlock();
1332 /***** CRITICAL SECTION END *****/
1333 return depth;
1334 }
1335
1336 /**
1337 * get_root_depth - return the depth of root directory.
1338 *
1339 * Returns number of directories to strip.
1340 */
1341 static int get_root_depth(void)
1342 {
1343 int depth;
1344 struct dentry *dentry;
1345 struct vfsmount *vfsmnt;
1346 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1347 struct path root;
1348 #endif
1349 /***** CRITICAL SECTION START *****/
1350 read_lock(&current->fs->lock);
1351 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1352 root = current->fs->root;
1353 path_get(&current->fs->root);
1354 dentry = root.dentry;
1355 vfsmnt = root.mnt;
1356 #else
1357 dentry = dget(current->fs->root);
1358 vfsmnt = mntget(current->fs->rootmnt);
1359 #endif
1360 read_unlock(&current->fs->lock);
1361 /***** CRITICAL SECTION END *****/
1362 depth = root_depth(dentry, vfsmnt);
1363 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1364 path_put(&root);
1365 #else
1366 dput(dentry);
1367 mntput(vfsmnt);
1368 #endif
1369 return depth;
1370 }
1371
1372 /**
1373 * try_alt_exec - Try to start execute handler.
1374 *
1375 * @r: Pointer to "struct ccs_request_info".
1376 * @handler: Pointer to the name of execute handler.
1377 * @eh_path: Pointer to pointer to the name of execute handler.
1378 *
1379 * Returns 0 on success, negative value otherwise.
1380 */
1381 static int try_alt_exec(struct ccs_request_info *r,
1382 const struct path_info *handler, char **eh_path)
1383 {
1384 /*
1385 * Contents of modified bprm.
1386 * The envp[] in original bprm is moved to argv[] so that
1387 * the alternatively executed program won't be affected by
1388 * some dangerous environment variables like LD_PRELOAD.
1389 *
1390 * modified bprm->argc
1391 * = original bprm->argc + original bprm->envc + 7
1392 * modified bprm->envc
1393 * = 0
1394 *
1395 * modified bprm->argv[0]
1396 * = the program's name specified by execute_handler
1397 * modified bprm->argv[1]
1398 * = current->domain_info->domainname->name
1399 * modified bprm->argv[2]
1400 * = the current process's name
1401 * modified bprm->argv[3]
1402 * = the current process's information (e.g. uid/gid).
1403 * modified bprm->argv[4]
1404 * = original bprm->filename
1405 * modified bprm->argv[5]
1406 * = original bprm->argc in string expression
1407 * modified bprm->argv[6]
1408 * = original bprm->envc in string expression
1409 * modified bprm->argv[7]
1410 * = original bprm->argv[0]
1411 * ...
1412 * modified bprm->argv[bprm->argc + 6]
1413 * = original bprm->argv[bprm->argc - 1]
1414 * modified bprm->argv[bprm->argc + 7]
1415 * = original bprm->envp[0]
1416 * ...
1417 * modified bprm->argv[bprm->envc + bprm->argc + 6]
1418 * = original bprm->envp[bprm->envc - 1]
1419 */
1420 struct linux_binprm *bprm = r->bprm;
1421 struct file *filp;
1422 int retval;
1423 const int original_argc = bprm->argc;
1424 const int original_envc = bprm->envc;
1425 struct task_struct *task = current;
1426 char *buffer = r->obj->tmp->buffer;
1427 /* Allocate memory for execute handler's pathname. */
1428 char *execute_handler = ccs_alloc(sizeof(struct ccs_page_buffer));
1429 *eh_path = execute_handler;
1430 if (!execute_handler)
1431 return -ENOMEM;
1432 strncpy(execute_handler, handler->name,
1433 sizeof(struct ccs_page_buffer) - 1);
1434 unescape(execute_handler);
1435
1436 /* Close the requested program's dentry. */
1437 allow_write_access(bprm->file);
1438 fput(bprm->file);
1439 bprm->file = NULL;
1440
1441 { /* Adjust root directory for open_exec(). */
1442 int depth = get_root_depth();
1443 char *cp = execute_handler;
1444 if (!*cp || *cp != '/')
1445 return -ENOENT;
1446 while (depth) {
1447 cp = strchr(cp + 1, '/');
1448 if (!cp)
1449 return -ENOENT;
1450 depth--;
1451 }
1452 memmove(execute_handler, cp, strlen(cp) + 1);
1453 }
1454
1455 /* Move envp[] to argv[] */
1456 bprm->argc += bprm->envc;
1457 bprm->envc = 0;
1458
1459 /* Set argv[6] */
1460 {
1461 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1462 original_envc);
1463 retval = copy_strings_kernel(1, &buffer, bprm);
1464 if (retval < 0)
1465 goto out;
1466 bprm->argc++;
1467 }
1468
1469 /* Set argv[5] */
1470 {
1471 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1472 original_argc);
1473 retval = copy_strings_kernel(1, &buffer, bprm);
1474 if (retval < 0)
1475 goto out;
1476 bprm->argc++;
1477 }
1478
1479 /* Set argv[4] */
1480 {
1481 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1482 if (retval < 0)
1483 goto out;
1484 bprm->argc++;
1485 }
1486
1487 /* Set argv[3] */
1488 {
1489 const u32 tomoyo_flags = task->tomoyo_flags;
1490 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1491 "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1492 "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1493 "state[1]=%u state[2]=%u",
1494 task->pid, task->uid, task->gid, task->euid,
1495 task->egid, task->suid, task->sgid, task->fsuid,
1496 task->fsgid, (u8) (tomoyo_flags >> 24),
1497 (u8) (tomoyo_flags >> 16), (u8) (tomoyo_flags >> 8));
1498 retval = copy_strings_kernel(1, &buffer, bprm);
1499 if (retval < 0)
1500 goto out;
1501 bprm->argc++;
1502 }
1503
1504 /* Set argv[2] */
1505 {
1506 char *exe = (char *) ccs_get_exe();
1507 if (exe) {
1508 retval = copy_strings_kernel(1, &exe, bprm);
1509 ccs_free(exe);
1510 } else {
1511 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1512 "<unknown>");
1513 retval = copy_strings_kernel(1, &buffer, bprm);
1514 }
1515 if (retval < 0)
1516 goto out;
1517 bprm->argc++;
1518 }
1519
1520 /* Set argv[1] */
1521 {
1522 strncpy(buffer, task->domain_info->domainname->name,
1523 sizeof(struct ccs_page_buffer) - 1);
1524 retval = copy_strings_kernel(1, &buffer, bprm);
1525 if (retval < 0)
1526 goto out;
1527 bprm->argc++;
1528 }
1529
1530 /* Set argv[0] */
1531 {
1532 retval = copy_strings_kernel(1, &execute_handler, bprm);
1533 if (retval < 0)
1534 goto out;
1535 bprm->argc++;
1536 }
1537 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1538 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1539 bprm->argv_len = bprm->exec - bprm->p;
1540 #endif
1541 #endif
1542
1543 /* OK, now restart the process with execute handler program's dentry. */
1544 filp = open_exec(execute_handler);
1545 if (IS_ERR(filp)) {
1546 retval = PTR_ERR(filp);
1547 goto out;
1548 }
1549 bprm->file = filp;
1550 bprm->filename = execute_handler;
1551 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1552 bprm->interp = execute_handler;
1553 #endif
1554 retval = prepare_binprm(bprm);
1555 if (retval < 0)
1556 goto out;
1557 task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1558 retval = find_next_domain(r, handler);
1559 task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1560 out:
1561 return retval;
1562 }
1563
1564 /**
1565 * find_execute_handler - Find an execute handler.
1566 *
1567 * @type: Type of execute handler.
1568 *
1569 * Returns pointer to "struct path_info" if found, NULL otherwise.
1570 */
1571 static const struct path_info *find_execute_handler(const u8 type)
1572 {
1573 struct task_struct *task = current;
1574 const struct domain_info *domain = task->domain_info;
1575 struct acl_info *ptr;
1576 /*
1577 * Don't use execute handler if the current process is
1578 * marked as execute handler to avoid infinite execute handler loop.
1579 */
1580 if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)
1581 return NULL;
1582 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
1583 struct execute_handler_record *acl;
1584 if (ptr->type != type)
1585 continue;
1586 acl = container_of(ptr, struct execute_handler_record, head);
1587 return acl->handler;
1588 }
1589 return NULL;
1590 }
1591
1592 /* List of next_domain which is used for checking interpreter's permissions. */
1593 struct execve_entry {
1594 struct list_head list;
1595 struct task_struct *task;
1596 struct domain_info *next_domain;
1597 };
1598
1599 static LIST_HEAD(execve_list);
1600 static DEFINE_SPINLOCK(execve_list_lock);
1601
1602 /**
1603 * ccs_register_next_domain - Remember next_domain.
1604 *
1605 * @next_domain: Pointer to "struct domain_info".
1606 *
1607 * Returns 0 on success, -ENOMEM otherwise.
1608 */
1609 static int ccs_register_next_domain(struct domain_info *next_domain)
1610 {
1611 struct execve_entry *ee = kmalloc(sizeof(*ee), GFP_KERNEL);
1612 if (!ee)
1613 return -ENOMEM;
1614 ee->task = current;
1615 ee->next_domain = next_domain;
1616 /***** CRITICAL SECTION START *****/
1617 spin_lock(&execve_list_lock);
1618 list_add(&ee->list, &execve_list);
1619 spin_unlock(&execve_list_lock);
1620 /***** CRITICAL SECTION END *****/
1621 return 0;
1622 }
1623
1624 /**
1625 * ccs_fetch_next_domain - Fetch next_domain from the list.
1626 *
1627 * Returns pointer to "struct domain_info" which will be used if execve()
1628 * succeeds. This function does not return NULL.
1629 */
1630 struct domain_info *ccs_fetch_next_domain(void)
1631 {
1632 struct task_struct *task = current;
1633 struct domain_info *next_domain = task->domain_info;
1634 struct execve_entry *p;
1635 /***** CRITICAL SECTION START *****/
1636 spin_lock(&execve_list_lock);
1637 list_for_each_entry(p, &execve_list, list) {
1638 if (p->task != task)
1639 continue;
1640 next_domain = p->next_domain;
1641 break;
1642 }
1643 spin_unlock(&execve_list_lock);
1644 /***** CRITICAL SECTION END *****/
1645 return next_domain;
1646 }
1647
1648 /**
1649 * ccs_unregister_next_domain - Forget next_domain.
1650 */
1651 static void ccs_unregister_next_domain(void)
1652 {
1653 struct task_struct *task = current;
1654 struct execve_entry *p;
1655 struct execve_entry *ee = NULL;
1656 /***** CRITICAL SECTION START *****/
1657 spin_lock(&execve_list_lock);
1658 list_for_each_entry(p, &execve_list, list) {
1659 if (p->task != task)
1660 continue;
1661 list_del(&p->list);
1662 ee = p;
1663 break;
1664 }
1665 spin_unlock(&execve_list_lock);
1666 /***** CRITICAL SECTION END *****/
1667 kfree(ee);
1668 }
1669
1670 /**
1671 * search_binary_handler_with_transition - Perform domain transition.
1672 *
1673 * @bprm: Pointer to "struct linux_binprm".
1674 * @regs: Pointer to "struct pt_regs".
1675 *
1676 * Returns result of search_binary_handler() on success,
1677 * negative value otherwise.
1678 */
1679 int search_binary_handler_with_transition(struct linux_binprm *bprm,
1680 struct pt_regs *regs)
1681 {
1682 int retval;
1683 struct task_struct *task = current;
1684 const struct path_info *handler;
1685 struct ccs_request_info r;
1686 struct obj_info obj;
1687 /*
1688 * "eh_path" holds path to execute handler program.
1689 * Thus, keep valid until search_binary_handler() finishes.
1690 */
1691 char *eh_path = NULL;
1692 struct ccs_page_buffer *tmp = ccs_alloc(sizeof(struct ccs_page_buffer));
1693 memset(&obj, 0, sizeof(obj));
1694 if (!sbin_init_started)
1695 ccs_load_policy(bprm->filename);
1696 if (!tmp)
1697 return -ENOMEM;
1698
1699 ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_FILE);
1700 r.bprm = bprm;
1701 r.obj = &obj;
1702 obj.path1_dentry = bprm->file->f_dentry;
1703 obj.path1_vfsmnt = bprm->file->f_vfsmnt;
1704 obj.tmp = tmp;
1705
1706 /* Clear manager flag. */
1707 task->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1708 handler = find_execute_handler(TYPE_EXECUTE_HANDLER);
1709 if (handler) {
1710 retval = try_alt_exec(&r, handler, &eh_path);
1711 if (!retval)
1712 audit_execute_handler_log(true, handler->name, bprm);
1713 goto ok;
1714 }
1715 retval = find_next_domain(&r, NULL);
1716 if (retval != -EPERM)
1717 goto ok;
1718 handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER);
1719 if (handler) {
1720 retval = try_alt_exec(&r, handler, &eh_path);
1721 if (!retval)
1722 audit_execute_handler_log(false, handler->name, bprm);
1723 }
1724 ok:
1725 if (retval < 0)
1726 goto out;
1727 r.mode = ccs_check_flags(r.domain, CCS_TOMOYO_MAC_FOR_ENV);
1728 retval = check_environ(&r);
1729 if (retval < 0)
1730 goto out;
1731 retval = ccs_register_next_domain(r.domain);
1732 if (retval < 0)
1733 goto out;
1734 task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1735 retval = search_binary_handler(bprm, regs);
1736 task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1737 if (retval < 0)
1738 goto out;
1739 /* Proceed to next domain if execution suceeded. */
1740 task->domain_info = r.domain;
1741 mb(); /* Make domain transition visible to other CPUs. */
1742 /* Mark the current process as execute handler. */
1743 if (handler)
1744 task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;
1745 /* Mark the current process as normal process. */
1746 else
1747 task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;
1748 out:
1749 ccs_unregister_next_domain();
1750 ccs_free(eh_path);
1751 ccs_free(tmp);
1752 return retval;
1753 }
1754
1755 #else
1756
1757 /**
1758 * search_binary_handler_with_transition - Wrapper for search_binary_handler().
1759 *
1760 * @bprm: Pointer to "struct linux_binprm".
1761 * @regs: Pointer to "struct pt_regs".
1762 *
1763 * Returns the result of search_binary_handler().
1764 */
1765 int search_binary_handler_with_transition(struct linux_binprm *bprm,
1766 struct pt_regs *regs)
1767 {
1768 #ifdef CONFIG_SAKURA
1769 /* Clear manager flag. */
1770 current->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1771 ccs_load_policy(bprm->filename);
1772 #endif
1773 return search_binary_handler(bprm, regs);
1774 }
1775
1776 #endif

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