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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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