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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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