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

Subversion リポジトリの参照

Contents of /branches/ccs-patch/fs/ccsecurity/domain.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2048 - (show annotations) (download) (as text)
Thu Jan 8 07:15:05 2009 UTC (15 years, 4 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/tomoyo_domain.c
File MIME type: text/x-csrc
File size: 47429 byte(s)


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

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