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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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