Open-Source-Software-Entwicklung und Downloads

Browse Subversion Repository

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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