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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1644 - (show annotations) (download) (as text)
Wed Oct 1 07:12:42 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: 45626 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/01
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 unsigned short int retries = 0;
1005 struct domain_info *old_domain = current->domain_info;
1006 struct domain_info *domain = NULL;
1007 const char *old_domain_name = old_domain->domainname->name;
1008 const char *original_name = bprm->filename;
1009 char *new_domain_name = NULL;
1010 char *real_program_name = NULL;
1011 char *symlink_program_name = NULL;
1012 const u8 mode = ccs_check_flags(CCS_TOMOYO_MAC_FOR_FILE);
1013 const bool is_enforce = (mode == 3);
1014 int retval;
1015 struct path_info r; /* real name */
1016 struct path_info s; /* symlink name */
1017 struct path_info l; /* last name */
1018 const u32 tomoyo_flags = current->tomoyo_flags;
1019
1020 {
1021 /*
1022 * Built-in initializers. This is needed because policies are
1023 * not loaded until starting /sbin/init.
1024 */
1025 static bool first = true;
1026 if (first) {
1027 update_domain_initializer_entry(NULL, "/sbin/hotplug",
1028 false, false);
1029 update_domain_initializer_entry(NULL, "/sbin/modprobe",
1030 false, false);
1031 first = false;
1032 }
1033 }
1034
1035 retry:
1036 current->tomoyo_flags = tomoyo_flags;
1037 /* Get ccs_realpath of program. */
1038 retval = -ENOENT; /* I hope ccs_realpath() won't fail with -ENOMEM. */
1039 ccs_free(real_program_name);
1040 real_program_name = ccs_realpath(original_name);
1041 if (!real_program_name)
1042 goto out;
1043 /* Get ccs_realpath of symbolic link. */
1044 ccs_free(symlink_program_name);
1045 symlink_program_name = ccs_realpath_nofollow(original_name);
1046 if (!symlink_program_name)
1047 goto out;
1048
1049 r.name = real_program_name;
1050 ccs_fill_path_info(&r);
1051 s.name = symlink_program_name;
1052 ccs_fill_path_info(&s);
1053 l.name = ccs_get_last_name(old_domain);
1054 ccs_fill_path_info(&l);
1055
1056 if (path_to_verify) {
1057 if (ccs_pathcmp(&r, path_to_verify)) {
1058 /* Failed to verify execute handler. */
1059 static u8 counter = 20;
1060 if (counter) {
1061 counter--;
1062 printk(KERN_WARNING "Failed to verify: %s\n",
1063 path_to_verify->name);
1064 }
1065 goto out;
1066 }
1067 goto calculate_domain;
1068 }
1069
1070 /* Check 'alias' directive. */
1071 if (ccs_pathcmp(&r, &s)) {
1072 struct alias_entry *ptr;
1073 /* Is this program allowed to be called via symbolic links? */
1074 list1_for_each_entry(ptr, &alias_list, list) {
1075 if (ptr->is_deleted ||
1076 ccs_pathcmp(&r, ptr->original_name) ||
1077 ccs_pathcmp(&s, ptr->aliased_name))
1078 continue;
1079 memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);
1080 strncpy(real_program_name, ptr->aliased_name->name,
1081 CCS_MAX_PATHNAME_LEN - 1);
1082 ccs_fill_path_info(&r);
1083 break;
1084 }
1085 }
1086
1087 /* Compare basename of real_program_name and argv[0] */
1088 if (bprm->argc > 0 && ccs_check_flags(CCS_TOMOYO_MAC_FOR_ARGV0)) {
1089 char *base_argv0 = tmp->buffer;
1090 const char *base_filename;
1091 retval = -ENOMEM;
1092 if (!get_argv0(bprm, tmp))
1093 goto out;
1094 base_filename = strrchr(real_program_name, '/');
1095 if (!base_filename)
1096 base_filename = real_program_name;
1097 else
1098 base_filename++;
1099 if (strcmp(base_argv0, base_filename)) {
1100 retval = ccs_check_argv0_perm(&r, base_argv0, retries);
1101 if (retval == 1) {
1102 retries++;
1103 goto retry;
1104 }
1105 retries = 0;
1106 if (retval < 0)
1107 goto out;
1108 }
1109 }
1110
1111 /* Check 'aggregator' directive. */
1112 {
1113 struct aggregator_entry *ptr;
1114 /* Is this program allowed to be aggregated? */
1115 list1_for_each_entry(ptr, &aggregator_list, list) {
1116 if (ptr->is_deleted ||
1117 !ccs_path_matches_pattern(&r, ptr->original_name))
1118 continue;
1119 memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);
1120 strncpy(real_program_name, ptr->aggregated_name->name,
1121 CCS_MAX_PATHNAME_LEN - 1);
1122 ccs_fill_path_info(&r);
1123 break;
1124 }
1125 }
1126
1127 /* Check execute permission. */
1128 retval = ccs_check_exec_perm(&r, bprm, tmp, retries);
1129 if (retval == 1) {
1130 retries++;
1131 goto retry;
1132 }
1133 retries = 0;
1134 if (retval < 0)
1135 goto out;
1136
1137 calculate_domain:
1138 new_domain_name = tmp->buffer;
1139 if (is_domain_initializer(old_domain->domainname, &r, &l)) {
1140 /* Transit to the child of KERNEL_DOMAIN domain. */
1141 snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,
1142 ROOT_NAME " " "%s", real_program_name);
1143 } else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) {
1144 /*
1145 * Needn't to transit from kernel domain before starting
1146 * /sbin/init. But transit from kernel domain if executing
1147 * initializers because they might start before /sbin/init.
1148 */
1149 domain = old_domain;
1150 } else if (is_domain_keeper(old_domain->domainname, &r, &l)) {
1151 /* Keep current domain. */
1152 domain = old_domain;
1153 } else {
1154 /* Normal domain transition. */
1155 snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,
1156 "%s %s", old_domain_name, real_program_name);
1157 }
1158 if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
1159 goto done;
1160 domain = ccs_find_domain(new_domain_name);
1161 if (domain)
1162 goto done;
1163 if (is_enforce) {
1164 int error = ccs_check_supervisor(retries, NULL,
1165 "# wants to create domain\n"
1166 "%s\n", new_domain_name);
1167 if (error == 1) {
1168 retries++;
1169 goto retry;
1170 }
1171 retries = 0;
1172 if (error < 0)
1173 goto done;
1174 }
1175 domain = ccs_find_or_assign_new_domain(new_domain_name,
1176 old_domain->profile);
1177 if (domain)
1178 audit_domain_creation_log(new_domain_name, mode,
1179 domain->profile);
1180 done:
1181 if (!domain) {
1182 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
1183 new_domain_name);
1184 if (is_enforce)
1185 retval = -EPERM;
1186 else {
1187 retval = 0;
1188 ccs_set_domain_flag(old_domain, false,
1189 DOMAIN_FLAGS_TRANSITION_FAILED);
1190 }
1191 } else {
1192 retval = 0;
1193 }
1194 out:
1195 ccs_free(real_program_name);
1196 ccs_free(symlink_program_name);
1197 *next_domain = domain ? domain : old_domain;
1198 return retval;
1199 }
1200
1201 /**
1202 * check_environ - Check permission for environment variable names.
1203 *
1204 * @bprm: Pointer to "struct linux_binprm".
1205 * @tmp: Buffer for temporal use.
1206 *
1207 * Returns 0 on success, negative value otherwise.
1208 */
1209 static int check_environ(struct linux_binprm *bprm, struct ccs_page_buffer *tmp)
1210 {
1211 const u8 profile = current->domain_info->profile;
1212 const u8 mode = ccs_check_flags(CCS_TOMOYO_MAC_FOR_ENV);
1213 char *arg_ptr = tmp->buffer;
1214 int arg_len = 0;
1215 unsigned long pos = bprm->p;
1216 int i = pos / PAGE_SIZE;
1217 int offset = pos % PAGE_SIZE;
1218 int argv_count = bprm->argc;
1219 int envp_count = bprm->envc;
1220 /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
1221 int error = -ENOMEM;
1222 if (!mode || !envp_count)
1223 return 0;
1224 while (error == -ENOMEM) {
1225 struct page *page;
1226 const char *kaddr;
1227 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1228 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page,
1229 NULL) <= 0)
1230 goto out;
1231 pos += PAGE_SIZE - offset;
1232 #else
1233 page = bprm->page[i];
1234 #endif
1235 /* Map. */
1236 kaddr = kmap(page);
1237 if (!kaddr) { /* Mapping failed. */
1238 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1239 put_page(page);
1240 #endif
1241 goto out;
1242 }
1243 /* Read. */
1244 while (argv_count && offset < PAGE_SIZE) {
1245 if (!kaddr[offset++])
1246 argv_count--;
1247 }
1248 if (argv_count)
1249 goto unmap_page;
1250 while (offset < PAGE_SIZE) {
1251 const unsigned char c = kaddr[offset++];
1252 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1253 if (c == '=') {
1254 arg_ptr[arg_len++] = '\0';
1255 } else if (c == '\\') {
1256 arg_ptr[arg_len++] = '\\';
1257 arg_ptr[arg_len++] = '\\';
1258 } else if (c > ' ' && c < 127) {
1259 arg_ptr[arg_len++] = c;
1260 } else {
1261 arg_ptr[arg_len++] = '\\';
1262 arg_ptr[arg_len++] = (c >> 6) + '0';
1263 arg_ptr[arg_len++]
1264 = ((c >> 3) & 7) + '0';
1265 arg_ptr[arg_len++] = (c & 7) + '0';
1266 }
1267 } else {
1268 arg_ptr[arg_len] = '\0';
1269 }
1270 if (c)
1271 continue;
1272 if (ccs_check_env_perm(arg_ptr, profile, mode)) {
1273 error = -EPERM;
1274 break;
1275 }
1276 if (!--envp_count) {
1277 error = 0;
1278 break;
1279 }
1280 arg_len = 0;
1281 }
1282 unmap_page:
1283 /* Unmap. */
1284 kunmap(page);
1285 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1286 put_page(page);
1287 #endif
1288 i++;
1289 offset = 0;
1290 }
1291 out:
1292 if (error && mode != 3)
1293 error = 0;
1294 return error;
1295 }
1296
1297 /**
1298 * unescape - Unescape escaped string.
1299 *
1300 * @dest: String to unescape.
1301 *
1302 * Returns nothing.
1303 */
1304 static void unescape(unsigned char *dest)
1305 {
1306 unsigned char *src = dest;
1307 unsigned char c;
1308 unsigned char d;
1309 unsigned char e;
1310 while ((c = *src++) != '\0') {
1311 if (c != '\\') {
1312 *dest++ = c;
1313 continue;
1314 }
1315 c = *src++;
1316 if (c == '\\') {
1317 *dest++ = c;
1318 continue;
1319 }
1320 if (c < '0' || c > '3')
1321 break;
1322 d = *src++;
1323 if (d < '0' || d > '7')
1324 break;
1325 e = *src++;
1326 if (e < '0' || e > '7')
1327 break;
1328 *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1329 }
1330 *dest = '\0';
1331 }
1332
1333 /**
1334 * root_depth - Get number of directories to strip.
1335 *
1336 * @dentry: Pointer to "struct dentry".
1337 * @vfsmnt: Pointer to "struct vfsmount".
1338 *
1339 * Returns number of directories to strip.
1340 */
1341 static inline int root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1342 {
1343 int depth = 0;
1344 /***** CRITICAL SECTION START *****/
1345 ccs_realpath_lock();
1346 for (;;) {
1347 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1348 /* Global root? */
1349 if (vfsmnt->mnt_parent == vfsmnt)
1350 break;
1351 dentry = vfsmnt->mnt_mountpoint;
1352 vfsmnt = vfsmnt->mnt_parent;
1353 continue;
1354 }
1355 dentry = dentry->d_parent;
1356 depth++;
1357 }
1358 ccs_realpath_unlock();
1359 /***** CRITICAL SECTION END *****/
1360 return depth;
1361 }
1362
1363 /**
1364 * get_root_depth - return the depth of root directory.
1365 *
1366 * Returns number of directories to strip.
1367 */
1368 static int get_root_depth(void)
1369 {
1370 int depth;
1371 struct dentry *dentry;
1372 struct vfsmount *vfsmnt;
1373 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1374 struct path root;
1375 #endif
1376 /***** CRITICAL SECTION START *****/
1377 read_lock(&current->fs->lock);
1378 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1379 root = current->fs->root;
1380 path_get(&current->fs->root);
1381 dentry = root.dentry;
1382 vfsmnt = root.mnt;
1383 #else
1384 dentry = dget(current->fs->root);
1385 vfsmnt = mntget(current->fs->rootmnt);
1386 #endif
1387 read_unlock(&current->fs->lock);
1388 /***** CRITICAL SECTION END *****/
1389 depth = root_depth(dentry, vfsmnt);
1390 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1391 path_put(&root);
1392 #else
1393 dput(dentry);
1394 mntput(vfsmnt);
1395 #endif
1396 return depth;
1397 }
1398
1399 /**
1400 * try_alt_exec - Try to start execute handler.
1401 *
1402 * @bprm: Pointer to "struct linux_binprm".
1403 * @handler: Pointer to the name of execute handler.
1404 * @eh_path: Pointer to pointer to the name of execute handler.
1405 * @next_domain: Pointer to pointer to "struct domain_info".
1406 * @tmp: Buffer for temporal use.
1407 *
1408 * Returns 0 on success, negative value otherwise.
1409 */
1410 static int try_alt_exec(struct linux_binprm *bprm,
1411 const struct path_info *handler, char **eh_path,
1412 struct domain_info **next_domain,
1413 struct ccs_page_buffer *tmp)
1414 {
1415 /*
1416 * Contents of modified bprm.
1417 * The envp[] in original bprm is moved to argv[] so that
1418 * the alternatively executed program won't be affected by
1419 * some dangerous environment variables like LD_PRELOAD.
1420 *
1421 * modified bprm->argc
1422 * = original bprm->argc + original bprm->envc + 7
1423 * modified bprm->envc
1424 * = 0
1425 *
1426 * modified bprm->argv[0]
1427 * = the program's name specified by execute_handler
1428 * modified bprm->argv[1]
1429 * = current->domain_info->domainname->name
1430 * modified bprm->argv[2]
1431 * = the current process's name
1432 * modified bprm->argv[3]
1433 * = the current process's information (e.g. uid/gid).
1434 * modified bprm->argv[4]
1435 * = original bprm->filename
1436 * modified bprm->argv[5]
1437 * = original bprm->argc in string expression
1438 * modified bprm->argv[6]
1439 * = original bprm->envc in string expression
1440 * modified bprm->argv[7]
1441 * = original bprm->argv[0]
1442 * ...
1443 * modified bprm->argv[bprm->argc + 6]
1444 * = original bprm->argv[bprm->argc - 1]
1445 * modified bprm->argv[bprm->argc + 7]
1446 * = original bprm->envp[0]
1447 * ...
1448 * modified bprm->argv[bprm->envc + bprm->argc + 6]
1449 * = original bprm->envp[bprm->envc - 1]
1450 */
1451 struct file *filp;
1452 int retval;
1453 const int original_argc = bprm->argc;
1454 const int original_envc = bprm->envc;
1455 struct task_struct *task = current;
1456 char *buffer = tmp->buffer;
1457 /* Allocate memory for execute handler's pathname. */
1458 char *execute_handler = ccs_alloc(sizeof(struct ccs_page_buffer));
1459 *eh_path = execute_handler;
1460 if (!execute_handler)
1461 return -ENOMEM;
1462 strncpy(execute_handler, handler->name,
1463 sizeof(struct ccs_page_buffer) - 1);
1464 unescape(execute_handler);
1465
1466 /* Close the requested program's dentry. */
1467 allow_write_access(bprm->file);
1468 fput(bprm->file);
1469 bprm->file = NULL;
1470
1471 { /* Adjust root directory for open_exec(). */
1472 int depth = get_root_depth();
1473 char *cp = execute_handler;
1474 if (!*cp || *cp != '/')
1475 return -ENOENT;
1476 while (depth) {
1477 cp = strchr(cp + 1, '/');
1478 if (!cp)
1479 return -ENOENT;
1480 depth--;
1481 }
1482 memmove(execute_handler, cp, strlen(cp) + 1);
1483 }
1484
1485 /* Move envp[] to argv[] */
1486 bprm->argc += bprm->envc;
1487 bprm->envc = 0;
1488
1489 /* Set argv[6] */
1490 {
1491 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1492 original_envc);
1493 retval = copy_strings_kernel(1, &buffer, bprm);
1494 if (retval < 0)
1495 goto out;
1496 bprm->argc++;
1497 }
1498
1499 /* Set argv[5] */
1500 {
1501 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1502 original_argc);
1503 retval = copy_strings_kernel(1, &buffer, bprm);
1504 if (retval < 0)
1505 goto out;
1506 bprm->argc++;
1507 }
1508
1509 /* Set argv[4] */
1510 {
1511 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1512 if (retval < 0)
1513 goto out;
1514 bprm->argc++;
1515 }
1516
1517 /* Set argv[3] */
1518 {
1519 const u32 tomoyo_flags = task->tomoyo_flags;
1520 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1521 "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1522 "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1523 "state[1]=%u state[2]=%u",
1524 task->pid, task->uid, task->gid, task->euid,
1525 task->egid, task->suid, task->sgid, task->fsuid,
1526 task->fsgid, (u8) (tomoyo_flags >> 24),
1527 (u8) (tomoyo_flags >> 16), (u8) (tomoyo_flags >> 8));
1528 retval = copy_strings_kernel(1, &buffer, bprm);
1529 if (retval < 0)
1530 goto out;
1531 bprm->argc++;
1532 }
1533
1534 /* Set argv[2] */
1535 {
1536 char *exe = (char *) ccs_get_exe();
1537 if (exe) {
1538 retval = copy_strings_kernel(1, &exe, bprm);
1539 ccs_free(exe);
1540 } else {
1541 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1542 "<unknown>");
1543 retval = copy_strings_kernel(1, &buffer, bprm);
1544 }
1545 if (retval < 0)
1546 goto out;
1547 bprm->argc++;
1548 }
1549
1550 /* Set argv[1] */
1551 {
1552 strncpy(buffer, task->domain_info->domainname->name,
1553 sizeof(struct ccs_page_buffer) - 1);
1554 retval = copy_strings_kernel(1, &buffer, bprm);
1555 if (retval < 0)
1556 goto out;
1557 bprm->argc++;
1558 }
1559
1560 /* Set argv[0] */
1561 {
1562 retval = copy_strings_kernel(1, &execute_handler, bprm);
1563 if (retval < 0)
1564 goto out;
1565 bprm->argc++;
1566 }
1567 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1568 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1569 bprm->argv_len = bprm->exec - bprm->p;
1570 #endif
1571 #endif
1572
1573 /* OK, now restart the process with execute handler program's dentry. */
1574 filp = open_exec(execute_handler);
1575 if (IS_ERR(filp)) {
1576 retval = PTR_ERR(filp);
1577 goto out;
1578 }
1579 bprm->file = filp;
1580 bprm->filename = execute_handler;
1581 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1582 bprm->interp = execute_handler;
1583 #endif
1584 retval = prepare_binprm(bprm);
1585 if (retval < 0)
1586 goto out;
1587 task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1588 retval = find_next_domain(bprm, next_domain, handler, tmp);
1589 task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1590 out:
1591 return retval;
1592 }
1593
1594 /**
1595 * find_execute_handler - Find an execute handler.
1596 *
1597 * @type: Type of execute handler.
1598 *
1599 * Returns pointer to "struct path_info" if found, NULL otherwise.
1600 */
1601 static const struct path_info *find_execute_handler(const u8 type)
1602 {
1603 struct task_struct *task = current;
1604 const struct domain_info *domain = task->domain_info;
1605 struct acl_info *ptr;
1606 /*
1607 * Don't use execute handler if the current process is
1608 * marked as execute handler to avoid infinite execute handler loop.
1609 */
1610 if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)
1611 return NULL;
1612 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
1613 struct execute_handler_record *acl;
1614 if (ptr->type != type)
1615 continue;
1616 acl = container_of(ptr, struct execute_handler_record, head);
1617 return acl->handler;
1618 }
1619 return NULL;
1620 }
1621
1622 /**
1623 * search_binary_handler_with_transition - Perform domain transition.
1624 *
1625 * @bprm: Pointer to "struct linux_binprm".
1626 * @regs: Pointer to "struct pt_regs".
1627 *
1628 * Returns result of search_binary_handler() on success,
1629 * negative value otherwise.
1630 */
1631 int search_binary_handler_with_transition(struct linux_binprm *bprm,
1632 struct pt_regs *regs)
1633 {
1634 struct task_struct *task = current;
1635 struct domain_info *next_domain = NULL;
1636 struct domain_info *prev_domain = task->domain_info;
1637 const struct path_info *handler;
1638 int retval;
1639 /*
1640 * "eh_path" holds path to execute handler program.
1641 * Thus, keep valid until search_binary_handler() finishes.
1642 */
1643 char *eh_path = NULL;
1644 struct ccs_page_buffer *tmp = ccs_alloc(sizeof(struct ccs_page_buffer));
1645 ccs_load_policy(bprm->filename);
1646 if (!tmp)
1647 return -ENOMEM;
1648 /* Clear manager flag. */
1649 task->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1650 /* printk(KERN_DEBUG "rootdepth=%d\n", get_root_depth()); */
1651 handler = find_execute_handler(TYPE_EXECUTE_HANDLER);
1652 if (handler) {
1653 retval = try_alt_exec(bprm, handler, &eh_path, &next_domain,
1654 tmp);
1655 if (!retval)
1656 audit_execute_handler_log(true, handler->name, bprm);
1657 goto ok;
1658 }
1659 retval = find_next_domain(bprm, &next_domain, NULL, tmp);
1660 if (retval != -EPERM)
1661 goto ok;
1662 handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER);
1663 if (handler) {
1664 retval = try_alt_exec(bprm, handler, &eh_path, &next_domain,
1665 tmp);
1666 if (!retval)
1667 audit_execute_handler_log(false, handler->name, bprm);
1668 }
1669 ok:
1670 if (retval < 0)
1671 goto out;
1672 task->domain_info = next_domain;
1673 retval = check_environ(bprm, tmp);
1674 if (retval < 0)
1675 goto out;
1676 task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1677 retval = search_binary_handler(bprm, regs);
1678 task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1679 out:
1680 /* Return to previous domain if execution failed. */
1681 if (retval < 0)
1682 task->domain_info = prev_domain;
1683 /* Mark the current process as execute handler. */
1684 else if (handler)
1685 task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;
1686 /* Mark the current process as normal process. */
1687 else
1688 task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;
1689 ccs_free(eh_path);
1690 ccs_free(tmp);
1691 return retval;
1692 }
1693
1694 #else
1695
1696 /**
1697 * search_binary_handler_with_transition - Wrapper for search_binary_handler().
1698 *
1699 * @bprm: Pointer to "struct linux_binprm".
1700 * @regs: Pointer to "struct pt_regs".
1701 *
1702 * Returns the result of search_binary_handler().
1703 */
1704 int search_binary_handler_with_transition(struct linux_binprm *bprm,
1705 struct pt_regs *regs)
1706 {
1707 #ifdef CONFIG_SAKURA
1708 /* Clear manager flag. */
1709 current->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1710 ccs_load_policy(bprm->filename);
1711 #endif
1712 return search_binary_handler(bprm, regs);
1713 }
1714
1715 #endif

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