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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1286 - (show annotations) (download) (as text)
Thu Jun 12 01:38:25 2008 UTC (15 years, 11 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/tomoyo_domain.c
File MIME type: text/x-csrc
File size: 45078 byte(s)
1.6.2-rc
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.2-rc 2008/06/12
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(NULL,
1148 "# wants to create domain\n%s\n",
1149 new_domain_name))
1150 goto done;
1151 domain = ccs_find_or_assign_new_domain(new_domain_name,
1152 old_domain->profile);
1153 if (domain)
1154 audit_domain_creation_log(new_domain_name, mode,
1155 domain->profile);
1156 done:
1157 if (!domain) {
1158 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
1159 new_domain_name);
1160 if (is_enforce)
1161 retval = -EPERM;
1162 else
1163 ccs_set_domain_flag(old_domain, false,
1164 DOMAIN_FLAGS_TRANSITION_FAILED);
1165 } else {
1166 retval = 0;
1167 }
1168 out:
1169 ccs_free(real_program_name);
1170 ccs_free(symlink_program_name);
1171 *next_domain = domain ? domain : old_domain;
1172 return retval;
1173 }
1174
1175 /**
1176 * check_environ - Check permission for environment variable names.
1177 *
1178 * @bprm: Pointer to "struct linux_binprm".
1179 * @tmp: Buffer for temporal use.
1180 *
1181 * Returns 0 on success, negative value otherwise.
1182 */
1183 static int check_environ(struct linux_binprm *bprm, struct ccs_page_buffer *tmp)
1184 {
1185 const u8 profile = current->domain_info->profile;
1186 const u8 mode = ccs_check_flags(CCS_TOMOYO_MAC_FOR_ENV);
1187 char *arg_ptr = tmp->buffer;
1188 int arg_len = 0;
1189 unsigned long pos = bprm->p;
1190 int i = pos / PAGE_SIZE;
1191 int offset = pos % PAGE_SIZE;
1192 int argv_count = bprm->argc;
1193 int envp_count = bprm->envc;
1194 /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
1195 int error = -ENOMEM;
1196 if (!mode || !envp_count)
1197 return 0;
1198 while (error == -ENOMEM) {
1199 struct page *page;
1200 const char *kaddr;
1201 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1202 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page,
1203 NULL) <= 0)
1204 goto out;
1205 pos += PAGE_SIZE - offset;
1206 #else
1207 page = bprm->page[i];
1208 #endif
1209 /* Map. */
1210 kaddr = kmap(page);
1211 if (!kaddr) { /* Mapping failed. */
1212 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1213 put_page(page);
1214 #endif
1215 goto out;
1216 }
1217 /* Read. */
1218 while (argv_count && offset < PAGE_SIZE) {
1219 if (!kaddr[offset++])
1220 argv_count--;
1221 }
1222 if (argv_count)
1223 goto unmap_page;
1224 while (offset < PAGE_SIZE) {
1225 const unsigned char c = kaddr[offset++];
1226 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1227 if (c == '=') {
1228 arg_ptr[arg_len++] = '\0';
1229 } else if (c == '\\') {
1230 arg_ptr[arg_len++] = '\\';
1231 arg_ptr[arg_len++] = '\\';
1232 } else if (c > ' ' && c < 127) {
1233 arg_ptr[arg_len++] = c;
1234 } else {
1235 arg_ptr[arg_len++] = '\\';
1236 arg_ptr[arg_len++] = (c >> 6) + '0';
1237 arg_ptr[arg_len++]
1238 = ((c >> 3) & 7) + '0';
1239 arg_ptr[arg_len++] = (c & 7) + '0';
1240 }
1241 } else {
1242 arg_ptr[arg_len] = '\0';
1243 }
1244 if (c)
1245 continue;
1246 if (ccs_check_env_perm(arg_ptr, profile, mode)) {
1247 error = -EPERM;
1248 break;
1249 }
1250 if (!--envp_count) {
1251 error = 0;
1252 break;
1253 }
1254 arg_len = 0;
1255 }
1256 unmap_page:
1257 /* Unmap. */
1258 kunmap(page);
1259 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1260 put_page(page);
1261 #endif
1262 i++;
1263 offset = 0;
1264 }
1265 out:
1266 if (error && mode != 3)
1267 error = 0;
1268 return error;
1269 }
1270
1271 /**
1272 * unescape - Unescape escaped string.
1273 *
1274 * @dest: String to unescape.
1275 *
1276 * Returns nothing.
1277 */
1278 static void unescape(unsigned char *dest)
1279 {
1280 unsigned char *src = dest;
1281 unsigned char c;
1282 unsigned char d;
1283 unsigned char e;
1284 while ((c = *src++) != '\0') {
1285 if (c != '\\') {
1286 *dest++ = c;
1287 continue;
1288 }
1289 c = *src++;
1290 if (c == '\\') {
1291 *dest++ = c;
1292 continue;
1293 }
1294 if (c < '0' || c > '3')
1295 break;
1296 d = *src++;
1297 if (d < '0' || d > '7')
1298 break;
1299 e = *src++;
1300 if (e < '0' || e > '7')
1301 break;
1302 *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1303 }
1304 *dest = '\0';
1305 }
1306
1307 /**
1308 * root_depth - Get number of directories to strip.
1309 *
1310 * @dentry: Pointer to "struct dentry".
1311 * @vfsmnt: Pointer to "struct vfsmount".
1312 *
1313 * Returns number of directories to strip.
1314 */
1315 static inline int root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1316 {
1317 int depth = 0;
1318 /***** CRITICAL SECTION START *****/
1319 spin_lock(&dcache_lock);
1320 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1321 spin_lock(&vfsmount_lock);
1322 #endif
1323 for (;;) {
1324 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1325 /* Global root? */
1326 if (vfsmnt->mnt_parent == vfsmnt)
1327 break;
1328 dentry = vfsmnt->mnt_mountpoint;
1329 vfsmnt = vfsmnt->mnt_parent;
1330 continue;
1331 }
1332 dentry = dentry->d_parent;
1333 depth++;
1334 }
1335 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1336 spin_unlock(&vfsmount_lock);
1337 #endif
1338 spin_unlock(&dcache_lock);
1339 /***** CRITICAL SECTION END *****/
1340 return depth;
1341 }
1342
1343 /**
1344 * get_root_depth - return the depth of root directory.
1345 *
1346 * Returns number of directories to strip.
1347 */
1348 static int get_root_depth(void)
1349 {
1350 int depth;
1351 struct dentry *dentry;
1352 struct vfsmount *vfsmnt;
1353 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1354 struct path root;
1355 #endif
1356 /***** CRITICAL SECTION START *****/
1357 read_lock(&current->fs->lock);
1358 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1359 root = current->fs->root;
1360 path_get(&current->fs->root);
1361 dentry = root.dentry;
1362 vfsmnt = root.mnt;
1363 #else
1364 dentry = dget(current->fs->root);
1365 vfsmnt = mntget(current->fs->rootmnt);
1366 #endif
1367 read_unlock(&current->fs->lock);
1368 /***** CRITICAL SECTION END *****/
1369 depth = root_depth(dentry, vfsmnt);
1370 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1371 path_put(&root);
1372 #else
1373 dput(dentry);
1374 mntput(vfsmnt);
1375 #endif
1376 return depth;
1377 }
1378
1379 /**
1380 * try_alt_exec - Try to start execute handler.
1381 *
1382 * @bprm: Pointer to "struct linux_binprm".
1383 * @filename: The name of requested program.
1384 * @work: Pointer to pointer to the name of execute handler.
1385 * @next_domain: Pointer to pointer to "struct domain_info".
1386 * @tmp: Buffer for temporal use.
1387 *
1388 * Returns 0 on success, negative value otherwise.
1389 */
1390 static int try_alt_exec(struct linux_binprm *bprm,
1391 const struct path_info *filename, char **work,
1392 struct domain_info **next_domain,
1393 struct ccs_page_buffer *tmp)
1394 {
1395 /*
1396 * Contents of modified bprm.
1397 * The envp[] in original bprm is moved to argv[] so that
1398 * the alternatively executed program won't be affected by
1399 * some dangerous environment variables like LD_PRELOAD.
1400 *
1401 * modified bprm->argc
1402 * = original bprm->argc + original bprm->envc + 7
1403 * modified bprm->envc
1404 * = 0
1405 *
1406 * modified bprm->argv[0]
1407 * = the program's name specified by execute_handler
1408 * modified bprm->argv[1]
1409 * = current->domain_info->domainname->name
1410 * modified bprm->argv[2]
1411 * = the current process's name
1412 * modified bprm->argv[3]
1413 * = the current process's information (e.g. uid/gid).
1414 * modified bprm->argv[4]
1415 * = original bprm->filename
1416 * modified bprm->argv[5]
1417 * = original bprm->argc in string expression
1418 * modified bprm->argv[6]
1419 * = original bprm->envc in string expression
1420 * modified bprm->argv[7]
1421 * = original bprm->argv[0]
1422 * ...
1423 * modified bprm->argv[bprm->argc + 6]
1424 * = original bprm->argv[bprm->argc - 1]
1425 * modified bprm->argv[bprm->argc + 7]
1426 * = original bprm->envp[0]
1427 * ...
1428 * modified bprm->argv[bprm->envc + bprm->argc + 6]
1429 * = original bprm->envp[bprm->envc - 1]
1430 */
1431 struct file *filp;
1432 int retval;
1433 const int original_argc = bprm->argc;
1434 const int original_envc = bprm->envc;
1435 struct task_struct *task = current;
1436 char *buffer = tmp->buffer;
1437 /* Allocate memory for execute handler's pathname. */
1438 char *execute_handler = ccs_alloc(sizeof(struct ccs_page_buffer));
1439 *work = execute_handler;
1440 if (!execute_handler)
1441 return -ENOMEM;
1442 strncpy(execute_handler, filename->name,
1443 sizeof(struct ccs_page_buffer) - 1);
1444 unescape(execute_handler);
1445
1446 /* Close the requested program's dentry. */
1447 allow_write_access(bprm->file);
1448 fput(bprm->file);
1449 bprm->file = NULL;
1450
1451 { /* Adjust root directory for open_exec(). */
1452 int depth = get_root_depth();
1453 char *cp = execute_handler;
1454 if (!*cp || *cp != '/')
1455 return -ENOENT;
1456 while (depth) {
1457 cp = strchr(cp + 1, '/');
1458 if (!cp)
1459 return -ENOENT;
1460 depth--;
1461 }
1462 memmove(execute_handler, cp, strlen(cp) + 1);
1463 }
1464
1465 /* Move envp[] to argv[] */
1466 bprm->argc += bprm->envc;
1467 bprm->envc = 0;
1468
1469 /* Set argv[6] */
1470 {
1471 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1472 original_envc);
1473 retval = copy_strings_kernel(1, &buffer, bprm);
1474 if (retval < 0)
1475 goto out;
1476 bprm->argc++;
1477 }
1478
1479 /* Set argv[5] */
1480 {
1481 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1482 original_argc);
1483 retval = copy_strings_kernel(1, &buffer, bprm);
1484 if (retval < 0)
1485 goto out;
1486 bprm->argc++;
1487 }
1488
1489 /* Set argv[4] */
1490 {
1491 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1492 if (retval < 0)
1493 goto out;
1494 bprm->argc++;
1495 }
1496
1497 /* Set argv[3] */
1498 {
1499 const u32 tomoyo_flags = task->tomoyo_flags;
1500 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1501 "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1502 "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1503 "state[1]=%u state[2]=%u",
1504 task->pid, task->uid, task->gid, task->euid,
1505 task->egid, task->suid, task->sgid, task->fsuid,
1506 task->fsgid, (u8) (tomoyo_flags >> 24),
1507 (u8) (tomoyo_flags >> 16), (u8) (tomoyo_flags >> 8));
1508 retval = copy_strings_kernel(1, &buffer, bprm);
1509 if (retval < 0)
1510 goto out;
1511 bprm->argc++;
1512 }
1513
1514 /* Set argv[2] */
1515 {
1516 char *exe = (char *) ccs_get_exe();
1517 if (exe) {
1518 retval = copy_strings_kernel(1, &exe, bprm);
1519 ccs_free(exe);
1520 } else {
1521 snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1522 "<unknown>");
1523 retval = copy_strings_kernel(1, &buffer, bprm);
1524 }
1525 if (retval < 0)
1526 goto out;
1527 bprm->argc++;
1528 }
1529
1530 /* Set argv[1] */
1531 {
1532 strncpy(buffer, task->domain_info->domainname->name,
1533 sizeof(struct ccs_page_buffer) - 1);
1534 retval = copy_strings_kernel(1, &buffer, bprm);
1535 if (retval < 0)
1536 goto out;
1537 bprm->argc++;
1538 }
1539
1540 /* Set argv[0] */
1541 {
1542 retval = copy_strings_kernel(1, &execute_handler, bprm);
1543 if (retval < 0)
1544 goto out;
1545 bprm->argc++;
1546 }
1547 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1548 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1549 bprm->argv_len = bprm->exec - bprm->p;
1550 #endif
1551 #endif
1552
1553 /* OK, now restart the process with execute handler program's dentry. */
1554 filp = open_exec(execute_handler);
1555 if (IS_ERR(filp)) {
1556 retval = PTR_ERR(filp);
1557 goto out;
1558 }
1559 bprm->file = filp;
1560 bprm->filename = execute_handler;
1561 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1562 bprm->interp = execute_handler;
1563 #endif
1564 retval = prepare_binprm(bprm);
1565 if (retval < 0)
1566 goto out;
1567 task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1568 retval = find_next_domain(bprm, next_domain, filename, tmp);
1569 task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1570 out:
1571 return retval;
1572 }
1573
1574 /**
1575 * find_execute_handler - Find an execute handler.
1576 *
1577 * @type: Type of execute handler.
1578 *
1579 * Returns pointer to "struct path_info" if found, NULL otherwise.
1580 */
1581 static const struct path_info *find_execute_handler(const u8 type)
1582 {
1583 struct task_struct *task = current;
1584 const struct domain_info *domain = task->domain_info;
1585 struct acl_info *ptr;
1586 /*
1587 * Don't use execute handler if the current process is
1588 * marked as execute handler to avoid infinite execute handler loop.
1589 */
1590 if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)
1591 return NULL;
1592 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
1593 struct execute_handler_record *acl;
1594 if (ptr->type != type)
1595 continue;
1596 acl = container_of(ptr, struct execute_handler_record, head);
1597 return acl->handler;
1598 }
1599 return NULL;
1600 }
1601
1602 /**
1603 * search_binary_handler_with_transition - Perform domain transition.
1604 *
1605 * @bprm: Pointer to "struct linux_binprm".
1606 * @regs: Pointer to "struct pt_regs".
1607 *
1608 * Returns result of search_binary_handler() on success,
1609 * negative value otherwise.
1610 */
1611 int search_binary_handler_with_transition(struct linux_binprm *bprm,
1612 struct pt_regs *regs)
1613 {
1614 struct task_struct *task = current;
1615 struct domain_info *next_domain = NULL;
1616 struct domain_info *prev_domain = task->domain_info;
1617 const struct path_info *handler;
1618 int retval;
1619 /*
1620 * "work" holds path to program.
1621 * Thus, keep valid until search_binary_handler() finishes.
1622 */
1623 char *work = NULL;
1624 struct ccs_page_buffer *buf = ccs_alloc(sizeof(struct ccs_page_buffer));
1625 ccs_load_policy(bprm->filename);
1626 if (!buf)
1627 return -ENOMEM;
1628 /* printk(KERN_DEBUG "rootdepth=%d\n", get_root_depth()); */
1629 handler = find_execute_handler(TYPE_EXECUTE_HANDLER);
1630 if (handler) {
1631 retval = try_alt_exec(bprm, handler, &work, &next_domain, buf);
1632 if (!retval)
1633 audit_execute_handler_log(true, work, bprm);
1634 goto ok;
1635 }
1636 retval = find_next_domain(bprm, &next_domain, NULL, buf);
1637 if (retval != -EPERM)
1638 goto ok;
1639 handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER);
1640 if (handler) {
1641 retval = try_alt_exec(bprm, handler, &work, &next_domain, buf);
1642 if (!retval)
1643 audit_execute_handler_log(false, work, bprm);
1644 }
1645 ok:
1646 if (retval)
1647 goto out;
1648 task->domain_info = next_domain;
1649 retval = check_environ(bprm, buf);
1650 if (retval)
1651 goto out;
1652 task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1653 retval = search_binary_handler(bprm, regs);
1654 task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1655 out:
1656 /* Return to previous domain if execution failed. */
1657 if (retval < 0)
1658 task->domain_info = prev_domain;
1659 /* Mark the current process as execute handler. */
1660 else if (handler)
1661 task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;
1662 /* Mark the current process as normal process. */
1663 else
1664 task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;
1665 ccs_free(work);
1666 ccs_free(buf);
1667 return retval;
1668 }
1669
1670 #else
1671
1672 /**
1673 * search_binary_handler_with_transition - Wrapper for search_binary_handler().
1674 *
1675 * @bprm: Pointer to "struct linux_binprm".
1676 * @regs: Pointer to "struct pt_regs".
1677 *
1678 * Returns the result of search_binary_handler().
1679 */
1680 int search_binary_handler_with_transition(struct linux_binprm *bprm,
1681 struct pt_regs *regs)
1682 {
1683 #ifdef CONFIG_SAKURA
1684 ccs_load_policy(bprm->filename);
1685 #endif
1686 return search_binary_handler(bprm, regs);
1687 }
1688
1689 #endif

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