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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2076 - (show annotations) (download) (as text)
Mon Jan 26 05:59:26 2009 UTC (15 years, 3 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/tomoyo_domain.c
File MIME type: text/x-csrc
File size: 47555 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_execve_entry".
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 u8 mode = r->mode;
956 const bool is_enforce = (mode == 3);
957 const u32 tomoyo_flags = current->tomoyo_flags;
958 char *new_domain_name = NULL;
959 struct ccs_path_info rn; /* real name */
960 struct ccs_path_info sn; /* symlink name */
961 struct ccs_path_info ln; /* last name */
962 int retval;
963
964 {
965 /*
966 * Built-in initializers. This is needed because policies are
967 * not loaded until starting /sbin/init.
968 */
969 static bool first = true;
970 if (first) {
971 ccs_update_domain_initializer_entry(NULL,
972 "/sbin/hotplug",
973 false, false);
974 ccs_update_domain_initializer_entry(NULL,
975 "/sbin/modprobe",
976 false, false);
977 first = false;
978 }
979 }
980
981 retry:
982 current->tomoyo_flags = tomoyo_flags;
983 r->cond = NULL;
984 /* Get realpath of program and symbolic link. */
985 retval = ccs_realpath_both(bprm->filename, ee);
986 if (retval < 0)
987 goto out;
988
989 rn.name = ee->program_path;
990 ccs_fill_path_info(&rn);
991 sn.name = ee->tmp;
992 ccs_fill_path_info(&sn);
993 ln.name = ccs_get_last_name(r->domain);
994 ccs_fill_path_info(&ln);
995
996 if (handler) {
997 if (ccs_pathcmp(&rn, handler)) {
998 /* Failed to verify execute handler. */
999 static u8 counter = 20;
1000 if (counter) {
1001 counter--;
1002 printk(KERN_WARNING "Failed to verify: %s\n",
1003 handler->name);
1004 }
1005 goto out;
1006 }
1007 goto calculate_domain;
1008 }
1009
1010 /* Check 'alias' directive. */
1011 if (ccs_pathcmp(&rn, &sn)) {
1012 struct ccs_alias_entry *ptr;
1013 /* Is this program allowed to be called via symbolic links? */
1014 list1_for_each_entry(ptr, &ccs_alias_list, list) {
1015 if (ptr->is_deleted ||
1016 ccs_pathcmp(&rn, ptr->original_name) ||
1017 ccs_pathcmp(&sn, ptr->aliased_name))
1018 continue;
1019 strncpy(ee->program_path, ptr->aliased_name->name,
1020 CCS_MAX_PATHNAME_LEN - 1);
1021 ccs_fill_path_info(&rn);
1022 break;
1023 }
1024 }
1025 /* sn will be overwritten after here. */
1026
1027 /* Compare basename of program_path and argv[0] */
1028 r->mode = ccs_check_flags(r->domain, CCS_TOMOYO_MAC_FOR_ARGV0);
1029 if (bprm->argc > 0 && r->mode) {
1030 char *base_argv0 = ee->tmp;
1031 const char *base_filename;
1032 retval = -ENOMEM;
1033 if (!ccs_get_argv0(ee))
1034 goto out;
1035 base_filename = strrchr(ee->program_path, '/');
1036 if (!base_filename)
1037 base_filename = ee->program_path;
1038 else
1039 base_filename++;
1040 if (strcmp(base_argv0, base_filename)) {
1041 retval = ccs_check_argv0_perm(r, &rn, base_argv0);
1042 if (retval == 1)
1043 goto retry;
1044 if (retval < 0)
1045 goto out;
1046 }
1047 }
1048
1049 /* Check 'aggregator' directive. */
1050 {
1051 struct ccs_aggregator_entry *ptr;
1052 /* Is this program allowed to be aggregated? */
1053 list1_for_each_entry(ptr, &ccs_aggregator_list, list) {
1054 if (ptr->is_deleted ||
1055 !ccs_path_matches_pattern(&rn, ptr->original_name))
1056 continue;
1057 strncpy(ee->program_path, ptr->aggregated_name->name,
1058 CCS_MAX_PATHNAME_LEN - 1);
1059 ccs_fill_path_info(&rn);
1060 break;
1061 }
1062 }
1063
1064 /* Check execute permission. */
1065 r->mode = mode;
1066 retval = ccs_check_exec_perm(r, &rn);
1067 if (retval == 1)
1068 goto retry;
1069 if (retval < 0)
1070 goto out;
1071
1072 calculate_domain:
1073 new_domain_name = ee->tmp;
1074 if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
1075 /* Transit to the child of KERNEL_DOMAIN domain. */
1076 snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
1077 ROOT_NAME " " "%s", ee->program_path);
1078 } else if (r->domain == &KERNEL_DOMAIN && !ccs_policy_loaded) {
1079 /*
1080 * Needn't to transit from kernel domain before starting
1081 * /sbin/init. But transit from kernel domain if executing
1082 * initializers because they might start before /sbin/init.
1083 */
1084 domain = r->domain;
1085 } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {
1086 /* Keep current domain. */
1087 domain = r->domain;
1088 } else {
1089 /* Normal domain transition. */
1090 snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
1091 "%s %s", old_domain_name, ee->program_path);
1092 }
1093 if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
1094 goto done;
1095 domain = ccs_find_domain(new_domain_name);
1096 if (domain)
1097 goto done;
1098 if (is_enforce) {
1099 int error = ccs_check_supervisor(r,
1100 "# wants to create domain\n"
1101 "%s\n", new_domain_name);
1102 if (error == 1)
1103 goto retry;
1104 if (error < 0)
1105 goto done;
1106 }
1107 domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);
1108 if (domain)
1109 ccs_audit_domain_creation_log(domain);
1110 done:
1111 if (!domain) {
1112 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
1113 new_domain_name);
1114 if (is_enforce)
1115 retval = -EPERM;
1116 else {
1117 retval = 0;
1118 ccs_set_domain_flag(r->domain, false,
1119 DOMAIN_FLAGS_TRANSITION_FAILED);
1120 }
1121 } else {
1122 retval = 0;
1123 }
1124 out:
1125 if (domain)
1126 r->domain = domain;
1127 return retval;
1128 }
1129
1130 /**
1131 * ccs_check_environ - Check permission for environment variable names.
1132 *
1133 * @ee: Pointer to "struct ccs_execve_entry".
1134 *
1135 * Returns 0 on success, negative value otherwise.
1136 */
1137 static int ccs_check_environ(struct ccs_execve_entry *ee)
1138 {
1139 struct ccs_request_info *r = &ee->r;
1140 struct linux_binprm *bprm = ee->bprm;
1141 char *arg_ptr = ee->tmp;
1142 int arg_len = 0;
1143 unsigned long pos = bprm->p;
1144 int offset = pos % PAGE_SIZE;
1145 int argv_count = bprm->argc;
1146 int envp_count = bprm->envc;
1147 /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
1148 int error = -ENOMEM;
1149 if (!r->mode || !envp_count)
1150 return 0;
1151 while (error == -ENOMEM) {
1152 if (!ccs_dump_page(bprm, pos, &ee->dump))
1153 goto out;
1154 pos += PAGE_SIZE - offset;
1155 /* Read. */
1156 while (argv_count && offset < PAGE_SIZE) {
1157 const char *kaddr = ee->dump.data;
1158 if (!kaddr[offset++])
1159 argv_count--;
1160 }
1161 if (argv_count) {
1162 offset = 0;
1163 continue;
1164 }
1165 while (offset < PAGE_SIZE) {
1166 const char *kaddr = ee->dump.data;
1167 const unsigned char c = kaddr[offset++];
1168 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1169 if (c == '=') {
1170 arg_ptr[arg_len++] = '\0';
1171 } else if (c == '\\') {
1172 arg_ptr[arg_len++] = '\\';
1173 arg_ptr[arg_len++] = '\\';
1174 } else if (c > ' ' && c < 127) {
1175 arg_ptr[arg_len++] = c;
1176 } else {
1177 arg_ptr[arg_len++] = '\\';
1178 arg_ptr[arg_len++] = (c >> 6) + '0';
1179 arg_ptr[arg_len++]
1180 = ((c >> 3) & 7) + '0';
1181 arg_ptr[arg_len++] = (c & 7) + '0';
1182 }
1183 } else {
1184 arg_ptr[arg_len] = '\0';
1185 }
1186 if (c)
1187 continue;
1188 if (ccs_check_env_perm(r, arg_ptr)) {
1189 error = -EPERM;
1190 break;
1191 }
1192 if (!--envp_count) {
1193 error = 0;
1194 break;
1195 }
1196 arg_len = 0;
1197 }
1198 offset = 0;
1199 }
1200 out:
1201 if (r->mode != 3)
1202 error = 0;
1203 return error;
1204 }
1205
1206 /**
1207 * ccs_unescape - Unescape escaped string.
1208 *
1209 * @dest: String to unescape.
1210 *
1211 * Returns nothing.
1212 */
1213 static void ccs_unescape(unsigned char *dest)
1214 {
1215 unsigned char *src = dest;
1216 unsigned char c;
1217 unsigned char d;
1218 unsigned char e;
1219 while (1) {
1220 c = *src++;
1221 if (!c)
1222 break;
1223 if (c != '\\') {
1224 *dest++ = c;
1225 continue;
1226 }
1227 c = *src++;
1228 if (c == '\\') {
1229 *dest++ = c;
1230 continue;
1231 }
1232 if (c < '0' || c > '3')
1233 break;
1234 d = *src++;
1235 if (d < '0' || d > '7')
1236 break;
1237 e = *src++;
1238 if (e < '0' || e > '7')
1239 break;
1240 *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1241 }
1242 *dest = '\0';
1243 }
1244
1245 /**
1246 * ccs_root_depth - Get number of directories to strip.
1247 *
1248 * @dentry: Pointer to "struct dentry".
1249 * @vfsmnt: Pointer to "struct vfsmount".
1250 *
1251 * Returns number of directories to strip.
1252 */
1253 static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1254 {
1255 int depth = 0;
1256 /***** CRITICAL SECTION START *****/
1257 ccs_realpath_lock();
1258 for (;;) {
1259 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1260 /* Global root? */
1261 if (vfsmnt->mnt_parent == vfsmnt)
1262 break;
1263 dentry = vfsmnt->mnt_mountpoint;
1264 vfsmnt = vfsmnt->mnt_parent;
1265 continue;
1266 }
1267 dentry = dentry->d_parent;
1268 depth++;
1269 }
1270 ccs_realpath_unlock();
1271 /***** CRITICAL SECTION END *****/
1272 return depth;
1273 }
1274
1275 /**
1276 * ccs_get_root_depth - return the depth of root directory.
1277 *
1278 * Returns number of directories to strip.
1279 */
1280 static int ccs_get_root_depth(void)
1281 {
1282 int depth;
1283 struct dentry *dentry;
1284 struct vfsmount *vfsmnt;
1285 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1286 struct path root;
1287 #endif
1288 /***** CRITICAL SECTION START *****/
1289 read_lock(&current->fs->lock);
1290 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1291 root = current->fs->root;
1292 path_get(&current->fs->root);
1293 dentry = root.dentry;
1294 vfsmnt = root.mnt;
1295 #else
1296 dentry = dget(current->fs->root);
1297 vfsmnt = mntget(current->fs->rootmnt);
1298 #endif
1299 read_unlock(&current->fs->lock);
1300 /***** CRITICAL SECTION END *****/
1301 depth = ccs_root_depth(dentry, vfsmnt);
1302 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1303 path_put(&root);
1304 #else
1305 dput(dentry);
1306 mntput(vfsmnt);
1307 #endif
1308 return depth;
1309 }
1310
1311 static LIST_HEAD(ccs_execve_list);
1312 static DEFINE_SPINLOCK(ccs_execve_list_lock);
1313
1314 /**
1315 * ccs_allocate_execve_entry - Allocate memory for execve().
1316 *
1317 * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1318 */
1319 static struct ccs_execve_entry *ccs_allocate_execve_entry(void)
1320 {
1321 struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);
1322 if (!ee)
1323 return NULL;
1324 memset(ee, 0, sizeof(*ee));
1325 ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1326 ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1327 if (!ee->program_path || !ee->tmp) {
1328 ccs_free(ee->program_path);
1329 ccs_free(ee->tmp);
1330 ccs_free(ee);
1331 return NULL;
1332 }
1333 /* ee->dump->data is allocated by ccs_dump_page(). */
1334 ee->task = current;
1335 /***** CRITICAL SECTION START *****/
1336 spin_lock(&ccs_execve_list_lock);
1337 list_add(&ee->list, &ccs_execve_list);
1338 spin_unlock(&ccs_execve_list_lock);
1339 /***** CRITICAL SECTION END *****/
1340 return ee;
1341 }
1342
1343 /**
1344 * ccs_find_execve_entry - Find ccs_execve_entry of current process.
1345 *
1346 * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1347 */
1348 static struct ccs_execve_entry *ccs_find_execve_entry(void)
1349 {
1350 struct task_struct *task = current;
1351 struct ccs_execve_entry *ee = NULL;
1352 struct ccs_execve_entry *p;
1353 /***** CRITICAL SECTION START *****/
1354 spin_lock(&ccs_execve_list_lock);
1355 list_for_each_entry(p, &ccs_execve_list, list) {
1356 if (p->task != task)
1357 continue;
1358 ee = p;
1359 break;
1360 }
1361 spin_unlock(&ccs_execve_list_lock);
1362 /***** CRITICAL SECTION END *****/
1363 return ee;
1364 }
1365
1366 /**
1367 * ccs_free_execve_entry - Free memory for execve().
1368 *
1369 * @ee: Pointer to "struct ccs_execve_entry".
1370 */
1371 static void ccs_free_execve_entry(struct ccs_execve_entry *ee)
1372 {
1373 if (!ee)
1374 return;
1375 /***** CRITICAL SECTION START *****/
1376 spin_lock(&ccs_execve_list_lock);
1377 list_del(&ee->list);
1378 spin_unlock(&ccs_execve_list_lock);
1379 /***** CRITICAL SECTION END *****/
1380 ccs_free(ee->program_path);
1381 ccs_free(ee->tmp);
1382 kfree(ee->dump.data);
1383 ccs_free(ee);
1384 }
1385
1386 /**
1387 * ccs_try_alt_exec - Try to start execute handler.
1388 *
1389 * @ee: Pointer to "struct ccs_execve_entry".
1390 *
1391 * Returns 0 on success, negative value otherwise.
1392 */
1393 static int ccs_try_alt_exec(struct ccs_execve_entry *ee)
1394 {
1395 /*
1396 * Contents of modified bprm.
1397 * The envp[] in original bprm is moved to argv[] so that
1398 * the alternatively executed program won't be affected by
1399 * some dangerous environment variables like LD_PRELOAD.
1400 *
1401 * modified bprm->argc
1402 * = original bprm->argc + original bprm->envc + 7
1403 * modified bprm->envc
1404 * = 0
1405 *
1406 * modified bprm->argv[0]
1407 * = the program's name specified by execute_handler
1408 * modified bprm->argv[1]
1409 * = current->domain_info->domainname->name
1410 * modified bprm->argv[2]
1411 * = the current process's name
1412 * modified bprm->argv[3]
1413 * = the current process's information (e.g. uid/gid).
1414 * modified bprm->argv[4]
1415 * = original bprm->filename
1416 * modified bprm->argv[5]
1417 * = original bprm->argc in string expression
1418 * modified bprm->argv[6]
1419 * = original bprm->envc in string expression
1420 * modified bprm->argv[7]
1421 * = original bprm->argv[0]
1422 * ...
1423 * modified bprm->argv[bprm->argc + 6]
1424 * = original bprm->argv[bprm->argc - 1]
1425 * modified bprm->argv[bprm->argc + 7]
1426 * = original bprm->envp[0]
1427 * ...
1428 * modified bprm->argv[bprm->envc + bprm->argc + 6]
1429 * = original bprm->envp[bprm->envc - 1]
1430 */
1431 struct linux_binprm *bprm = ee->bprm;
1432 struct file *filp;
1433 int retval;
1434 const int original_argc = bprm->argc;
1435 const int original_envc = bprm->envc;
1436 struct task_struct *task = current;
1437
1438 /* Close the requested program's dentry. */
1439 allow_write_access(bprm->file);
1440 fput(bprm->file);
1441 bprm->file = NULL;
1442
1443 /* Invalidate page dump cache. */
1444 ee->dump.page = NULL;
1445
1446 /* Move envp[] to argv[] */
1447 bprm->argc += bprm->envc;
1448 bprm->envc = 0;
1449
1450 /* Set argv[6] */
1451 {
1452 char *cp = ee->tmp;
1453 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
1454 retval = copy_strings_kernel(1, &cp, bprm);
1455 if (retval < 0)
1456 goto out;
1457 bprm->argc++;
1458 }
1459
1460 /* Set argv[5] */
1461 {
1462 char *cp = ee->tmp;
1463 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
1464 retval = copy_strings_kernel(1, &cp, bprm);
1465 if (retval < 0)
1466 goto out;
1467 bprm->argc++;
1468 }
1469
1470 /* Set argv[4] */
1471 {
1472 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1473 if (retval < 0)
1474 goto out;
1475 bprm->argc++;
1476 }
1477
1478 /* Set argv[3] */
1479 {
1480 char *cp = ee->tmp;
1481 const u32 tomoyo_flags = task->tomoyo_flags;
1482 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1483 "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1484 "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1485 "state[1]=%u state[2]=%u",
1486 (pid_t) sys_getpid(), current_uid(), current_gid(),
1487 current_euid(), current_egid(), current_suid(),
1488 current_sgid(), current_fsuid(), current_fsgid(),
1489 (u8) (tomoyo_flags >> 24), (u8) (tomoyo_flags >> 16),
1490 (u8) (tomoyo_flags >> 8));
1491 retval = copy_strings_kernel(1, &cp, bprm);
1492 if (retval < 0)
1493 goto out;
1494 bprm->argc++;
1495 }
1496
1497 /* Set argv[2] */
1498 {
1499 char *exe = (char *) ccs_get_exe();
1500 if (exe) {
1501 retval = copy_strings_kernel(1, &exe, bprm);
1502 ccs_free(exe);
1503 } else {
1504 exe = ee->tmp;
1505 strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);
1506 retval = copy_strings_kernel(1, &exe, bprm);
1507 }
1508 if (retval < 0)
1509 goto out;
1510 bprm->argc++;
1511 }
1512
1513 /* Set argv[1] */
1514 {
1515 char *cp = ee->tmp;
1516 strncpy(ee->tmp, task->domain_info->domainname->name,
1517 CCS_EXEC_TMPSIZE - 1);
1518 retval = copy_strings_kernel(1, &cp, bprm);
1519 if (retval < 0)
1520 goto out;
1521 bprm->argc++;
1522 }
1523
1524 /* Set argv[0] */
1525 {
1526 int depth = ccs_get_root_depth();
1527 char *cp = ee->program_path;
1528 strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);
1529 ccs_unescape(cp);
1530 retval = -ENOENT;
1531 if (!*cp || *cp != '/')
1532 goto out;
1533 /* Adjust root directory for open_exec(). */
1534 while (depth) {
1535 cp = strchr(cp + 1, '/');
1536 if (!cp)
1537 goto out;
1538 depth--;
1539 }
1540 memmove(ee->program_path, cp, strlen(cp) + 1);
1541 cp = ee->program_path;
1542 retval = copy_strings_kernel(1, &cp, bprm);
1543 if (retval < 0)
1544 goto out;
1545 bprm->argc++;
1546 }
1547 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1548 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1549 bprm->argv_len = bprm->exec - bprm->p;
1550 #endif
1551 #endif
1552
1553 /* OK, now restart the process with execute handler program's dentry. */
1554 filp = open_exec(ee->program_path);
1555 if (IS_ERR(filp)) {
1556 retval = PTR_ERR(filp);
1557 goto out;
1558 }
1559 bprm->file = filp;
1560 bprm->filename = ee->program_path;
1561 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1562 bprm->interp = bprm->filename;
1563 #endif
1564 retval = prepare_binprm(bprm);
1565 if (retval < 0)
1566 goto out;
1567 {
1568 /*
1569 * Backup ee->program_path because ccs_find_next_domain() will
1570 * overwrite ee->program_path and ee->tmp.
1571 */
1572 const int len = strlen(ee->program_path) + 1;
1573 char *cp = kmalloc(len, GFP_KERNEL);
1574 if (!cp) {
1575 retval = -ENOMEM;
1576 goto out;
1577 }
1578 memmove(cp, ee->program_path, len);
1579 bprm->filename = cp;
1580 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1581 bprm->interp = bprm->filename;
1582 #endif
1583 task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1584 retval = ccs_find_next_domain(ee);
1585 task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1586 /* Restore ee->program_path for search_binary_handler(). */
1587 memmove(ee->program_path, cp, len);
1588 bprm->filename = ee->program_path;
1589 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1590 bprm->interp = bprm->filename;
1591 #endif
1592 kfree(cp);
1593 }
1594 out:
1595 return retval;
1596 }
1597
1598 /**
1599 * ccs_find_execute_handler - Find an execute handler.
1600 *
1601 * @ee: Pointer to "struct ccs_execve_entry".
1602 * @type: Type of execute handler.
1603 *
1604 * Returns true if found, false otherwise.
1605 */
1606 static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1607 const u8 type)
1608 {
1609 struct task_struct *task = current;
1610 const struct domain_info *domain = task->domain_info;
1611 struct ccs_acl_info *ptr;
1612 /*
1613 * Don't use execute handler if the current process is
1614 * marked as execute handler to avoid infinite execute handler loop.
1615 */
1616 if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)
1617 return false;
1618 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
1619 struct ccs_execute_handler_record *acl;
1620 if (ptr->type != type)
1621 continue;
1622 acl = container_of(ptr, struct ccs_execute_handler_record,
1623 head);
1624 ee->handler = acl->handler;
1625 return true;
1626 }
1627 return false;
1628 }
1629
1630 /**
1631 * ccs_dump_page - Dump a page to buffer.
1632 *
1633 * @bprm: Pointer to "struct linux_binprm".
1634 * @pos: Location to dump.
1635 * @dump: Poiner to "struct ccs_page_dump".
1636 *
1637 * Returns true on success, false otherwise.
1638 */
1639 bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1640 struct ccs_page_dump *dump)
1641 {
1642 struct page *page;
1643 /* dump->data is released by ccs_free_execve_entry(). */
1644 if (!dump->data) {
1645 dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL);
1646 if (!dump->data)
1647 return false;
1648 }
1649 /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1650 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1651 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1652 return false;
1653 #else
1654 page = bprm->page[pos / PAGE_SIZE];
1655 #endif
1656 if (page != dump->page) {
1657 const unsigned int offset = pos % PAGE_SIZE;
1658 /*
1659 * Maybe kmap()/kunmap() should be used here.
1660 * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1661 * So do I.
1662 */
1663 char *kaddr = kmap_atomic(page, KM_USER0);
1664 dump->page = page;
1665 memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);
1666 kunmap_atomic(kaddr, KM_USER0);
1667 }
1668 /* Same with put_arg_page(page) in fs/exec.c */
1669 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1670 put_page(page);
1671 #endif
1672 return true;
1673 }
1674
1675 /**
1676 * ccs_fetch_next_domain - Fetch next_domain from the list.
1677 *
1678 * Returns pointer to "struct domain_info" which will be used if execve()
1679 * succeeds. This function does not return NULL.
1680 */
1681 struct domain_info *ccs_fetch_next_domain(void)
1682 {
1683 struct ccs_execve_entry *ee = ccs_find_execve_entry();
1684 struct domain_info *next_domain = NULL;
1685 if (ee)
1686 next_domain = ee->next_domain;
1687 if (!next_domain)
1688 next_domain = current->domain_info;
1689 return next_domain;
1690 }
1691
1692 /**
1693 * ccs_start_execve - Prepare for execve() operation.
1694 *
1695 * @bprm: Pointer to "struct linux_binprm".
1696 *
1697 * Returns 0 on success, negative value otherwise.
1698 */
1699 int ccs_start_execve(struct linux_binprm *bprm)
1700 {
1701 int retval;
1702 struct task_struct *task = current;
1703 struct ccs_execve_entry *ee = ccs_allocate_execve_entry();
1704 if (!ccs_policy_loaded)
1705 ccs_load_policy(bprm->filename);
1706 if (!ee)
1707 return -ENOMEM;
1708 ccs_init_request_info(&ee->r, NULL, CCS_TOMOYO_MAC_FOR_FILE);
1709 ee->r.ee = ee;
1710 ee->bprm = bprm;
1711 ee->r.obj = &ee->obj;
1712 ee->obj.path1_dentry = bprm->file->f_dentry;
1713 ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;
1714 /* Clear manager flag. */
1715 task->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1716 if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {
1717 retval = ccs_try_alt_exec(ee);
1718 if (!retval)
1719 ccs_audit_execute_handler_log(ee, true);
1720 goto ok;
1721 }
1722 retval = ccs_find_next_domain(ee);
1723 if (retval != -EPERM)
1724 goto ok;
1725 if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {
1726 retval = ccs_try_alt_exec(ee);
1727 if (!retval)
1728 ccs_audit_execute_handler_log(ee, false);
1729 }
1730 ok:
1731 if (retval < 0)
1732 goto out;
1733 ee->r.mode = ccs_check_flags(ee->r.domain, CCS_TOMOYO_MAC_FOR_ENV);
1734 retval = ccs_check_environ(ee);
1735 if (retval < 0)
1736 goto out;
1737 ee->next_domain = ee->r.domain;
1738 task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1739 retval = 0;
1740 out:
1741 if (retval)
1742 ccs_finish_execve(retval);
1743 return retval;
1744 }
1745
1746 /**
1747 * ccs_finish_execve - Clean up execve() operation.
1748 *
1749 * @retval: Return code of an execve() operation.
1750 */
1751 void ccs_finish_execve(int retval)
1752 {
1753 struct task_struct *task = current;
1754 struct ccs_execve_entry *ee = ccs_find_execve_entry();
1755 task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1756 if (!ee)
1757 return;
1758 if (retval < 0)
1759 goto out;
1760 /* Proceed to next domain if execution suceeded. */
1761 task->domain_info = ee->r.domain;
1762 mb(); /* Make domain transition visible to other CPUs. */
1763 /* Mark the current process as execute handler. */
1764 if (ee->handler)
1765 task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;
1766 /* Mark the current process as normal process. */
1767 else
1768 task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;
1769 out:
1770 ccs_free_execve_entry(ee);
1771 }
1772
1773 #else
1774
1775 /**
1776 * ccs_start_execve - Prepare for execve() operation.
1777 *
1778 * @bprm: Pointer to "struct linux_binprm".
1779 *
1780 * Returns 0.
1781 */
1782 int ccs_start_execve(struct linux_binprm *bprm)
1783 {
1784 #ifdef CONFIG_SAKURA
1785 /* Clear manager flag. */
1786 current->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1787 if (!ccs_policy_loaded)
1788 ccs_load_policy(bprm->filename);
1789 #endif
1790 return 0;
1791 }
1792
1793 /**
1794 * ccs_finish_execve - Clean up execve() operation.
1795 */
1796 void ccs_finish_execve(int retval)
1797 {
1798 }
1799
1800 #endif

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