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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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