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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2393 - (show annotations) (download) (as text)
Mon Apr 6 05:24:05 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: 45094 byte(s)
Drop "undelete domain" command. Escape invalid characters in ccs_check_mount_permission2().
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 handler. */
709
710 /**
711 * ccs_delete_domain - Delete a domain.
712 *
713 * @domainname: The name of domain.
714 *
715 * Returns 0.
716 */
717 int ccs_delete_domain(char *domainname)
718 {
719 struct ccs_domain_info *domain;
720 struct ccs_path_info name;
721 name.name = domainname;
722 ccs_fill_path_info(&name);
723 mutex_lock(&ccs_domain_list_lock);
724 /* Is there an active domain? */
725 list1_for_each_entry(domain, &ccs_domain_list, list) {
726 /* Never delete ccs_kernel_domain */
727 if (domain == &ccs_kernel_domain)
728 continue;
729 if (domain->is_deleted ||
730 ccs_pathcmp(domain->domainname, &name))
731 continue;
732 domain->is_deleted = true;
733 break;
734 }
735 mutex_unlock(&ccs_domain_list_lock);
736 return 0;
737 }
738
739 /**
740 * ccs_find_or_assign_new_domain - Create a domain.
741 *
742 * @domainname: The name of domain.
743 * @profile: Profile number to assign if the domain was newly created.
744 *
745 * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
746 */
747 struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,
748 const u8 profile)
749 {
750 struct ccs_domain_info *domain = NULL;
751 const struct ccs_path_info *saved_domainname;
752 mutex_lock(&ccs_domain_list_lock);
753 domain = ccs_find_domain(domainname);
754 if (domain)
755 goto out;
756 if (!ccs_is_correct_domain(domainname, __func__))
757 goto out;
758 saved_domainname = ccs_save_name(domainname);
759 if (!saved_domainname)
760 goto out;
761 /* Can I reuse memory of deleted domain? */
762 list1_for_each_entry(domain, &ccs_domain_list, list) {
763 struct task_struct *p;
764 struct ccs_acl_info *ptr;
765 bool flag;
766 if (!domain->is_deleted ||
767 domain->domainname != saved_domainname)
768 continue;
769 flag = false;
770 /***** CRITICAL SECTION START *****/
771 read_lock(&tasklist_lock);
772 for_each_process(p) {
773 if (ccs_task_domain(p) != domain)
774 continue;
775 flag = true;
776 break;
777 }
778 read_unlock(&tasklist_lock);
779 /***** CRITICAL SECTION END *****/
780 if (flag)
781 continue;
782 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
783 ptr->type |= ACL_DELETED;
784 }
785 ccs_set_domain_flag(domain, true, domain->flags);
786 domain->profile = profile;
787 domain->quota_warned = false;
788 mb(); /* Avoid out-of-order execution. */
789 domain->is_deleted = false;
790 goto out;
791 }
792 /* No memory reusable. Create using new memory. */
793 domain = ccs_alloc_element(sizeof(*domain));
794 if (domain) {
795 INIT_LIST1_HEAD(&domain->acl_info_list);
796 domain->domainname = saved_domainname;
797 domain->profile = profile;
798 list1_add_tail_mb(&domain->list, &ccs_domain_list);
799 }
800 out:
801 mutex_unlock(&ccs_domain_list_lock);
802 return domain;
803 }
804
805 /**
806 * ccs_get_argv0 - Get argv[0].
807 *
808 * @ee: Pointer to "struct ccs_execve_entry".
809 *
810 * Returns true on success, false otherwise.
811 */
812 static bool ccs_get_argv0(struct ccs_execve_entry *ee)
813 {
814 struct linux_binprm *bprm = ee->bprm;
815 char *arg_ptr = ee->tmp;
816 int arg_len = 0;
817 unsigned long pos = bprm->p;
818 int offset = pos % PAGE_SIZE;
819 bool done = false;
820 if (!bprm->argc)
821 goto out;
822 while (1) {
823 if (!ccs_dump_page(bprm, pos, &ee->dump))
824 goto out;
825 pos += PAGE_SIZE - offset;
826 /* Read. */
827 while (offset < PAGE_SIZE) {
828 const char *kaddr = ee->dump.data;
829 const unsigned char c = kaddr[offset++];
830 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
831 if (c == '\\') {
832 arg_ptr[arg_len++] = '\\';
833 arg_ptr[arg_len++] = '\\';
834 } else if (c == '/') {
835 arg_len = 0;
836 } else if (c > ' ' && c < 127) {
837 arg_ptr[arg_len++] = c;
838 } else {
839 arg_ptr[arg_len++] = '\\';
840 arg_ptr[arg_len++] = (c >> 6) + '0';
841 arg_ptr[arg_len++]
842 = ((c >> 3) & 7) + '0';
843 arg_ptr[arg_len++] = (c & 7) + '0';
844 }
845 } else {
846 arg_ptr[arg_len] = '\0';
847 done = true;
848 break;
849 }
850 }
851 offset = 0;
852 if (done)
853 break;
854 }
855 return true;
856 out:
857 return false;
858 }
859
860 /**
861 * ccs_find_next_domain - Find a domain.
862 *
863 * @ee: Pointer to "struct ccs_execve_entry".
864 *
865 * Returns 0 on success, negative value otherwise.
866 */
867 static int ccs_find_next_domain(struct ccs_execve_entry *ee)
868 {
869 struct ccs_request_info *r = &ee->r;
870 const struct ccs_path_info *handler = ee->handler;
871 struct ccs_domain_info *domain = NULL;
872 const char *old_domain_name = r->domain->domainname->name;
873 struct linux_binprm *bprm = ee->bprm;
874 const u8 mode = r->mode;
875 const bool is_enforce = (mode == 3);
876 const u32 ccs_flags = current->ccs_flags;
877 char *new_domain_name = NULL;
878 struct ccs_path_info rn; /* real name */
879 struct ccs_path_info sn; /* symlink name */
880 struct ccs_path_info ln; /* last name */
881 int retval;
882 retry:
883 current->ccs_flags = ccs_flags;
884 r->cond = NULL;
885 /* Get realpath of program and symbolic link. */
886 retval = ccs_realpath_both(bprm->filename, ee);
887 if (retval < 0)
888 goto out;
889
890 rn.name = ee->program_path;
891 ccs_fill_path_info(&rn);
892 sn.name = ee->tmp;
893 ccs_fill_path_info(&sn);
894 ln.name = ccs_get_last_name(r->domain);
895 ccs_fill_path_info(&ln);
896
897 if (handler) {
898 if (ccs_pathcmp(&rn, handler)) {
899 /* Failed to verify execute handler. */
900 static u8 counter = 20;
901 if (counter) {
902 counter--;
903 printk(KERN_WARNING "Failed to verify: %s\n",
904 handler->name);
905 }
906 goto out;
907 }
908 goto calculate_domain;
909 }
910
911 /* Check 'alias' directive. */
912 if (ccs_pathcmp(&rn, &sn)) {
913 struct ccs_alias_entry *ptr;
914 /* Is this program allowed to be called via symbolic links? */
915 list1_for_each_entry(ptr, &ccs_alias_list, list) {
916 if (ptr->is_deleted ||
917 ccs_pathcmp(&rn, ptr->original_name) ||
918 ccs_pathcmp(&sn, ptr->aliased_name))
919 continue;
920 strncpy(ee->program_path, ptr->aliased_name->name,
921 CCS_MAX_PATHNAME_LEN - 1);
922 ccs_fill_path_info(&rn);
923 break;
924 }
925 }
926 /* sn will be overwritten after here. */
927
928 /* Compare basename of program_path and argv[0] */
929 r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_ARGV0);
930 if (bprm->argc > 0 && r->mode) {
931 char *base_argv0 = ee->tmp;
932 const char *base_filename;
933 retval = -ENOMEM;
934 if (!ccs_get_argv0(ee))
935 goto out;
936 base_filename = strrchr(ee->program_path, '/');
937 if (!base_filename)
938 base_filename = ee->program_path;
939 else
940 base_filename++;
941 if (strcmp(base_argv0, base_filename)) {
942 retval = ccs_check_argv0_perm(r, &rn, base_argv0);
943 if (retval == 1)
944 goto retry;
945 if (retval < 0)
946 goto out;
947 }
948 }
949
950 /* Check 'aggregator' directive. */
951 {
952 struct ccs_aggregator_entry *ptr;
953 /* Is this program allowed to be aggregated? */
954 list1_for_each_entry(ptr, &ccs_aggregator_list, list) {
955 if (ptr->is_deleted ||
956 !ccs_path_matches_pattern(&rn, ptr->original_name))
957 continue;
958 strncpy(ee->program_path, ptr->aggregated_name->name,
959 CCS_MAX_PATHNAME_LEN - 1);
960 ccs_fill_path_info(&rn);
961 break;
962 }
963 }
964
965 /* Check execute permission. */
966 r->mode = mode;
967 retval = ccs_check_exec_perm(r, &rn);
968 if (retval == 1)
969 goto retry;
970 if (retval < 0)
971 goto out;
972
973 calculate_domain:
974 new_domain_name = ee->tmp;
975 if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
976 /* Transit to the child of ccs_kernel_domain domain. */
977 snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
978 ROOT_NAME " " "%s", ee->program_path);
979 } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
980 /*
981 * Needn't to transit from kernel domain before starting
982 * /sbin/init. But transit from kernel domain if executing
983 * initializers because they might start before /sbin/init.
984 */
985 domain = r->domain;
986 } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {
987 /* Keep current domain. */
988 domain = r->domain;
989 } else {
990 /* Normal domain transition. */
991 snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
992 "%s %s", old_domain_name, ee->program_path);
993 }
994 if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
995 goto done;
996 domain = ccs_find_domain(new_domain_name);
997 if (domain)
998 goto done;
999 if (is_enforce) {
1000 int error = ccs_check_supervisor(r,
1001 "# wants to create domain\n"
1002 "%s\n", new_domain_name);
1003 if (error == 1)
1004 goto retry;
1005 if (error < 0)
1006 goto done;
1007 }
1008 domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);
1009 if (domain)
1010 ccs_audit_domain_creation_log(domain);
1011 done:
1012 if (!domain) {
1013 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
1014 new_domain_name);
1015 if (is_enforce)
1016 retval = -EPERM;
1017 else {
1018 retval = 0;
1019 ccs_set_domain_flag(r->domain, false,
1020 DOMAIN_FLAGS_TRANSITION_FAILED);
1021 }
1022 } else {
1023 retval = 0;
1024 }
1025 out:
1026 if (domain)
1027 r->domain = domain;
1028 return retval;
1029 }
1030
1031 /**
1032 * ccs_check_environ - Check permission for environment variable names.
1033 *
1034 * @ee: Pointer to "struct ccs_execve_entry".
1035 *
1036 * Returns 0 on success, negative value otherwise.
1037 */
1038 static int ccs_check_environ(struct ccs_execve_entry *ee)
1039 {
1040 struct ccs_request_info *r = &ee->r;
1041 struct linux_binprm *bprm = ee->bprm;
1042 char *arg_ptr = ee->tmp;
1043 int arg_len = 0;
1044 unsigned long pos = bprm->p;
1045 int offset = pos % PAGE_SIZE;
1046 int argv_count = bprm->argc;
1047 int envp_count = bprm->envc;
1048 /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
1049 int error = -ENOMEM;
1050 if (!r->mode || !envp_count)
1051 return 0;
1052 while (error == -ENOMEM) {
1053 if (!ccs_dump_page(bprm, pos, &ee->dump))
1054 goto out;
1055 pos += PAGE_SIZE - offset;
1056 /* Read. */
1057 while (argv_count && offset < PAGE_SIZE) {
1058 const char *kaddr = ee->dump.data;
1059 if (!kaddr[offset++])
1060 argv_count--;
1061 }
1062 if (argv_count) {
1063 offset = 0;
1064 continue;
1065 }
1066 while (offset < PAGE_SIZE) {
1067 const char *kaddr = ee->dump.data;
1068 const unsigned char c = kaddr[offset++];
1069 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1070 if (c == '=') {
1071 arg_ptr[arg_len++] = '\0';
1072 } else if (c == '\\') {
1073 arg_ptr[arg_len++] = '\\';
1074 arg_ptr[arg_len++] = '\\';
1075 } else if (c > ' ' && c < 127) {
1076 arg_ptr[arg_len++] = c;
1077 } else {
1078 arg_ptr[arg_len++] = '\\';
1079 arg_ptr[arg_len++] = (c >> 6) + '0';
1080 arg_ptr[arg_len++]
1081 = ((c >> 3) & 7) + '0';
1082 arg_ptr[arg_len++] = (c & 7) + '0';
1083 }
1084 } else {
1085 arg_ptr[arg_len] = '\0';
1086 }
1087 if (c)
1088 continue;
1089 if (ccs_check_env_perm(r, arg_ptr)) {
1090 error = -EPERM;
1091 break;
1092 }
1093 if (!--envp_count) {
1094 error = 0;
1095 break;
1096 }
1097 arg_len = 0;
1098 }
1099 offset = 0;
1100 }
1101 out:
1102 if (r->mode != 3)
1103 error = 0;
1104 return error;
1105 }
1106
1107 /**
1108 * ccs_unescape - Unescape escaped string.
1109 *
1110 * @dest: String to unescape.
1111 *
1112 * Returns nothing.
1113 */
1114 static void ccs_unescape(unsigned char *dest)
1115 {
1116 unsigned char *src = dest;
1117 unsigned char c;
1118 unsigned char d;
1119 unsigned char e;
1120 while (1) {
1121 c = *src++;
1122 if (!c)
1123 break;
1124 if (c != '\\') {
1125 *dest++ = c;
1126 continue;
1127 }
1128 c = *src++;
1129 if (c == '\\') {
1130 *dest++ = c;
1131 continue;
1132 }
1133 if (c < '0' || c > '3')
1134 break;
1135 d = *src++;
1136 if (d < '0' || d > '7')
1137 break;
1138 e = *src++;
1139 if (e < '0' || e > '7')
1140 break;
1141 *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1142 }
1143 *dest = '\0';
1144 }
1145
1146 /**
1147 * ccs_root_depth - Get number of directories to strip.
1148 *
1149 * @dentry: Pointer to "struct dentry".
1150 * @vfsmnt: Pointer to "struct vfsmount".
1151 *
1152 * Returns number of directories to strip.
1153 */
1154 static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1155 {
1156 int depth = 0;
1157 /***** CRITICAL SECTION START *****/
1158 ccs_realpath_lock();
1159 for (;;) {
1160 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1161 /* Global root? */
1162 if (vfsmnt->mnt_parent == vfsmnt)
1163 break;
1164 dentry = vfsmnt->mnt_mountpoint;
1165 vfsmnt = vfsmnt->mnt_parent;
1166 continue;
1167 }
1168 dentry = dentry->d_parent;
1169 depth++;
1170 }
1171 ccs_realpath_unlock();
1172 /***** CRITICAL SECTION END *****/
1173 return depth;
1174 }
1175
1176 /**
1177 * ccs_get_root_depth - return the depth of root directory.
1178 *
1179 * Returns number of directories to strip.
1180 */
1181 static int ccs_get_root_depth(void)
1182 {
1183 int depth;
1184 struct dentry *dentry;
1185 struct vfsmount *vfsmnt;
1186 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1187 struct path root;
1188 #endif
1189 /***** CRITICAL SECTION START *****/
1190 read_lock(&current->fs->lock);
1191 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1192 root = current->fs->root;
1193 path_get(&current->fs->root);
1194 dentry = root.dentry;
1195 vfsmnt = root.mnt;
1196 #else
1197 dentry = dget(current->fs->root);
1198 vfsmnt = mntget(current->fs->rootmnt);
1199 #endif
1200 read_unlock(&current->fs->lock);
1201 /***** CRITICAL SECTION END *****/
1202 depth = ccs_root_depth(dentry, vfsmnt);
1203 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1204 path_put(&root);
1205 #else
1206 dput(dentry);
1207 mntput(vfsmnt);
1208 #endif
1209 return depth;
1210 }
1211
1212 static LIST_HEAD(ccs_execve_list);
1213 static DEFINE_SPINLOCK(ccs_execve_list_lock);
1214
1215 /**
1216 * ccs_allocate_execve_entry - Allocate memory for execve().
1217 *
1218 * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1219 */
1220 static struct ccs_execve_entry *ccs_allocate_execve_entry(void)
1221 {
1222 struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);
1223 if (!ee)
1224 return NULL;
1225 memset(ee, 0, sizeof(*ee));
1226 ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1227 ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1228 if (!ee->program_path || !ee->tmp) {
1229 ccs_free(ee->program_path);
1230 ccs_free(ee->tmp);
1231 ccs_free(ee);
1232 return NULL;
1233 }
1234 /* ee->dump->data is allocated by ccs_dump_page(). */
1235 ee->task = current;
1236 /***** CRITICAL SECTION START *****/
1237 spin_lock(&ccs_execve_list_lock);
1238 list_add(&ee->list, &ccs_execve_list);
1239 spin_unlock(&ccs_execve_list_lock);
1240 /***** CRITICAL SECTION END *****/
1241 return ee;
1242 }
1243
1244 /**
1245 * ccs_find_execve_entry - Find ccs_execve_entry of current process.
1246 *
1247 * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1248 */
1249 static struct ccs_execve_entry *ccs_find_execve_entry(void)
1250 {
1251 struct task_struct *task = current;
1252 struct ccs_execve_entry *ee = NULL;
1253 struct ccs_execve_entry *p;
1254 /***** CRITICAL SECTION START *****/
1255 spin_lock(&ccs_execve_list_lock);
1256 list_for_each_entry(p, &ccs_execve_list, list) {
1257 if (p->task != task)
1258 continue;
1259 ee = p;
1260 break;
1261 }
1262 spin_unlock(&ccs_execve_list_lock);
1263 /***** CRITICAL SECTION END *****/
1264 return ee;
1265 }
1266
1267 /**
1268 * ccs_free_execve_entry - Free memory for execve().
1269 *
1270 * @ee: Pointer to "struct ccs_execve_entry".
1271 */
1272 static void ccs_free_execve_entry(struct ccs_execve_entry *ee)
1273 {
1274 if (!ee)
1275 return;
1276 /***** CRITICAL SECTION START *****/
1277 spin_lock(&ccs_execve_list_lock);
1278 list_del(&ee->list);
1279 spin_unlock(&ccs_execve_list_lock);
1280 /***** CRITICAL SECTION END *****/
1281 ccs_free(ee->program_path);
1282 ccs_free(ee->tmp);
1283 kfree(ee->dump.data);
1284 ccs_free(ee);
1285 }
1286
1287 /**
1288 * ccs_try_alt_exec - Try to start execute handler.
1289 *
1290 * @ee: Pointer to "struct ccs_execve_entry".
1291 *
1292 * Returns 0 on success, negative value otherwise.
1293 */
1294 static int ccs_try_alt_exec(struct ccs_execve_entry *ee)
1295 {
1296 /*
1297 * Contents of modified bprm.
1298 * The envp[] in original bprm is moved to argv[] so that
1299 * the alternatively executed program won't be affected by
1300 * some dangerous environment variables like LD_PRELOAD.
1301 *
1302 * modified bprm->argc
1303 * = original bprm->argc + original bprm->envc + 7
1304 * modified bprm->envc
1305 * = 0
1306 *
1307 * modified bprm->argv[0]
1308 * = the program's name specified by execute_handler
1309 * modified bprm->argv[1]
1310 * = ccs_current_domain()->domainname->name
1311 * modified bprm->argv[2]
1312 * = the current process's name
1313 * modified bprm->argv[3]
1314 * = the current process's information (e.g. uid/gid).
1315 * modified bprm->argv[4]
1316 * = original bprm->filename
1317 * modified bprm->argv[5]
1318 * = original bprm->argc in string expression
1319 * modified bprm->argv[6]
1320 * = original bprm->envc in string expression
1321 * modified bprm->argv[7]
1322 * = original bprm->argv[0]
1323 * ...
1324 * modified bprm->argv[bprm->argc + 6]
1325 * = original bprm->argv[bprm->argc - 1]
1326 * modified bprm->argv[bprm->argc + 7]
1327 * = original bprm->envp[0]
1328 * ...
1329 * modified bprm->argv[bprm->envc + bprm->argc + 6]
1330 * = original bprm->envp[bprm->envc - 1]
1331 */
1332 struct linux_binprm *bprm = ee->bprm;
1333 struct file *filp;
1334 int retval;
1335 const int original_argc = bprm->argc;
1336 const int original_envc = bprm->envc;
1337 struct task_struct *task = current;
1338
1339 /* Close the requested program's dentry. */
1340 allow_write_access(bprm->file);
1341 fput(bprm->file);
1342 bprm->file = NULL;
1343
1344 /* Invalidate page dump cache. */
1345 ee->dump.page = NULL;
1346
1347 /* Move envp[] to argv[] */
1348 bprm->argc += bprm->envc;
1349 bprm->envc = 0;
1350
1351 /* Set argv[6] */
1352 {
1353 char *cp = ee->tmp;
1354 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
1355 retval = copy_strings_kernel(1, &cp, bprm);
1356 if (retval < 0)
1357 goto out;
1358 bprm->argc++;
1359 }
1360
1361 /* Set argv[5] */
1362 {
1363 char *cp = ee->tmp;
1364 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
1365 retval = copy_strings_kernel(1, &cp, bprm);
1366 if (retval < 0)
1367 goto out;
1368 bprm->argc++;
1369 }
1370
1371 /* Set argv[4] */
1372 {
1373 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1374 if (retval < 0)
1375 goto out;
1376 bprm->argc++;
1377 }
1378
1379 /* Set argv[3] */
1380 {
1381 char *cp = ee->tmp;
1382 const u32 ccs_flags = task->ccs_flags;
1383 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1384 "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1385 "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1386 "state[1]=%u state[2]=%u",
1387 (pid_t) sys_getpid(), current_uid(), current_gid(),
1388 current_euid(), current_egid(), current_suid(),
1389 current_sgid(), current_fsuid(), current_fsgid(),
1390 (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
1391 (u8) (ccs_flags >> 8));
1392 retval = copy_strings_kernel(1, &cp, bprm);
1393 if (retval < 0)
1394 goto out;
1395 bprm->argc++;
1396 }
1397
1398 /* Set argv[2] */
1399 {
1400 char *exe = (char *) ccs_get_exe();
1401 if (exe) {
1402 retval = copy_strings_kernel(1, &exe, bprm);
1403 ccs_free(exe);
1404 } else {
1405 exe = ee->tmp;
1406 strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);
1407 retval = copy_strings_kernel(1, &exe, bprm);
1408 }
1409 if (retval < 0)
1410 goto out;
1411 bprm->argc++;
1412 }
1413
1414 /* Set argv[1] */
1415 {
1416 char *cp = ee->tmp;
1417 strncpy(ee->tmp, ccs_current_domain()->domainname->name,
1418 CCS_EXEC_TMPSIZE - 1);
1419 retval = copy_strings_kernel(1, &cp, bprm);
1420 if (retval < 0)
1421 goto out;
1422 bprm->argc++;
1423 }
1424
1425 /* Set argv[0] */
1426 {
1427 int depth = ccs_get_root_depth();
1428 char *cp = ee->program_path;
1429 strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);
1430 ccs_unescape(cp);
1431 retval = -ENOENT;
1432 if (!*cp || *cp != '/')
1433 goto out;
1434 /* Adjust root directory for open_exec(). */
1435 while (depth) {
1436 cp = strchr(cp + 1, '/');
1437 if (!cp)
1438 goto out;
1439 depth--;
1440 }
1441 memmove(ee->program_path, cp, strlen(cp) + 1);
1442 cp = ee->program_path;
1443 retval = copy_strings_kernel(1, &cp, bprm);
1444 if (retval < 0)
1445 goto out;
1446 bprm->argc++;
1447 }
1448 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1449 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1450 bprm->argv_len = bprm->exec - bprm->p;
1451 #endif
1452 #endif
1453
1454 /* OK, now restart the process with execute handler program's dentry. */
1455 filp = open_exec(ee->program_path);
1456 if (IS_ERR(filp)) {
1457 retval = PTR_ERR(filp);
1458 goto out;
1459 }
1460 bprm->file = filp;
1461 bprm->filename = ee->program_path;
1462 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1463 bprm->interp = bprm->filename;
1464 #endif
1465 retval = prepare_binprm(bprm);
1466 if (retval < 0)
1467 goto out;
1468 {
1469 /*
1470 * Backup ee->program_path because ccs_find_next_domain() will
1471 * overwrite ee->program_path and ee->tmp.
1472 */
1473 const int len = strlen(ee->program_path) + 1;
1474 char *cp = kmalloc(len, GFP_KERNEL);
1475 if (!cp) {
1476 retval = -ENOMEM;
1477 goto out;
1478 }
1479 memmove(cp, ee->program_path, len);
1480 bprm->filename = cp;
1481 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1482 bprm->interp = bprm->filename;
1483 #endif
1484 task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1485 retval = ccs_find_next_domain(ee);
1486 task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1487 /* Restore ee->program_path for search_binary_handler(). */
1488 memmove(ee->program_path, cp, len);
1489 bprm->filename = ee->program_path;
1490 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1491 bprm->interp = bprm->filename;
1492 #endif
1493 kfree(cp);
1494 }
1495 out:
1496 return retval;
1497 }
1498
1499 /**
1500 * ccs_find_execute_handler - Find an execute handler.
1501 *
1502 * @ee: Pointer to "struct ccs_execve_entry".
1503 * @type: Type of execute handler.
1504 *
1505 * Returns true if found, false otherwise.
1506 */
1507 static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1508 const u8 type)
1509 {
1510 struct task_struct *task = current;
1511 const struct ccs_domain_info *domain = ccs_current_domain();
1512 struct ccs_acl_info *ptr;
1513 /*
1514 * Don't use execute handler if the current process is
1515 * marked as execute handler to avoid infinite execute handler loop.
1516 */
1517 if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1518 return false;
1519 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
1520 struct ccs_execute_handler_record *acl;
1521 if (ptr->type != type)
1522 continue;
1523 acl = container_of(ptr, struct ccs_execute_handler_record,
1524 head);
1525 ee->handler = acl->handler;
1526 return true;
1527 }
1528 return false;
1529 }
1530
1531 /**
1532 * ccs_dump_page - Dump a page to buffer.
1533 *
1534 * @bprm: Pointer to "struct linux_binprm".
1535 * @pos: Location to dump.
1536 * @dump: Poiner to "struct ccs_page_dump".
1537 *
1538 * Returns true on success, false otherwise.
1539 */
1540 bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1541 struct ccs_page_dump *dump)
1542 {
1543 struct page *page;
1544 /* dump->data is released by ccs_free_execve_entry(). */
1545 if (!dump->data) {
1546 dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL);
1547 if (!dump->data)
1548 return false;
1549 }
1550 /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1551 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1552 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1553 return false;
1554 #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1555 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1556 return false;
1557 #else
1558 page = bprm->page[pos / PAGE_SIZE];
1559 #endif
1560 if (page != dump->page) {
1561 const unsigned int offset = pos % PAGE_SIZE;
1562 /*
1563 * Maybe kmap()/kunmap() should be used here.
1564 * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1565 * So do I.
1566 */
1567 char *kaddr = kmap_atomic(page, KM_USER0);
1568 dump->page = page;
1569 memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);
1570 kunmap_atomic(kaddr, KM_USER0);
1571 }
1572 /* Same with put_arg_page(page) in fs/exec.c */
1573 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1574 put_page(page);
1575 #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1576 put_page(page);
1577 #endif
1578 return true;
1579 }
1580
1581 /**
1582 * ccs_fetch_next_domain - Fetch next_domain from the list.
1583 *
1584 * Returns pointer to "struct ccs_domain_info" which will be used if execve()
1585 * succeeds. This function does not return NULL.
1586 */
1587 struct ccs_domain_info *ccs_fetch_next_domain(void)
1588 {
1589 struct ccs_execve_entry *ee = ccs_find_execve_entry();
1590 struct ccs_domain_info *next_domain = NULL;
1591 if (ee)
1592 next_domain = ee->next_domain;
1593 if (!next_domain)
1594 next_domain = ccs_current_domain();
1595 return next_domain;
1596 }
1597
1598 /**
1599 * ccs_start_execve - Prepare for execve() operation.
1600 *
1601 * @bprm: Pointer to "struct linux_binprm".
1602 *
1603 * Returns 0 on success, negative value otherwise.
1604 */
1605 int ccs_start_execve(struct linux_binprm *bprm)
1606 {
1607 int retval;
1608 struct task_struct *task = current;
1609 struct ccs_execve_entry *ee = ccs_allocate_execve_entry();
1610 if (!ccs_policy_loaded)
1611 ccs_load_policy(bprm->filename);
1612 if (!ee)
1613 return -ENOMEM;
1614 ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);
1615 ee->r.ee = ee;
1616 ee->bprm = bprm;
1617 ee->r.obj = &ee->obj;
1618 ee->obj.path1_dentry = bprm->file->f_dentry;
1619 ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;
1620 /* Clear manager flag. */
1621 task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1622 if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {
1623 retval = ccs_try_alt_exec(ee);
1624 if (!retval)
1625 ccs_audit_execute_handler_log(ee, true);
1626 goto ok;
1627 }
1628 retval = ccs_find_next_domain(ee);
1629 if (retval != -EPERM)
1630 goto ok;
1631 if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {
1632 retval = ccs_try_alt_exec(ee);
1633 if (!retval)
1634 ccs_audit_execute_handler_log(ee, false);
1635 }
1636 ok:
1637 if (retval < 0)
1638 goto out;
1639 ee->r.mode = ccs_check_flags(ee->r.domain, CCS_MAC_FOR_ENV);
1640 retval = ccs_check_environ(ee);
1641 if (retval < 0)
1642 goto out;
1643 ee->next_domain = ee->r.domain;
1644 task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;
1645 retval = 0;
1646 out:
1647 if (retval)
1648 ccs_finish_execve(retval);
1649 return retval;
1650 }
1651
1652 /**
1653 * ccs_finish_execve - Clean up execve() operation.
1654 *
1655 * @retval: Return code of an execve() operation.
1656 */
1657 void ccs_finish_execve(int retval)
1658 {
1659 struct task_struct *task = current;
1660 struct ccs_execve_entry *ee = ccs_find_execve_entry();
1661 task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;
1662 if (!ee)
1663 return;
1664 if (retval < 0)
1665 goto out;
1666 /* Proceed to next domain if execution suceeded. */
1667 task->ccs_domain_info = ee->r.domain;
1668 mb(); /* Make domain transition visible to other CPUs. */
1669 /* Mark the current process as execute handler. */
1670 if (ee->handler)
1671 task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1672 /* Mark the current process as normal process. */
1673 else
1674 task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1675 out:
1676 ccs_free_execve_entry(ee);
1677 }
1678
1679 #else
1680
1681 /**
1682 * ccs_start_execve - Prepare for execve() operation.
1683 *
1684 * @bprm: Pointer to "struct linux_binprm".
1685 *
1686 * Returns 0.
1687 */
1688 int ccs_start_execve(struct linux_binprm *bprm)
1689 {
1690 #ifdef CONFIG_SAKURA
1691 /* Clear manager flag. */
1692 current->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1693 if (!ccs_policy_loaded)
1694 ccs_load_policy(bprm->filename);
1695 #endif
1696 return 0;
1697 }
1698
1699 /**
1700 * ccs_finish_execve - Clean up execve() operation.
1701 */
1702 void ccs_finish_execve(int retval)
1703 {
1704 }
1705
1706 #endif

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