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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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