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

Subversion リポジトリの参照

Contents of /branches/ccs-patch/fs/tomoyo_domain.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2703 - (show annotations) (download) (as text)
Tue Jun 30 04:43:11 2009 UTC (14 years, 11 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 43175 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 /**
41 * ccs_get_last_name - Get last component of a domainname.
42 *
43 * @domain: Pointer to "struct ccs_domain_info".
44 *
45 * Returns the last component of the domainname.
46 */
47 const char *ccs_get_last_name(const struct ccs_domain_info *domain)
48 {
49 const char *cp0 = domain->domainname->name;
50 const char *cp1 = strrchr(cp0, ' ');
51 if (cp1)
52 return cp1 + 1;
53 return cp0;
54 }
55
56 /**
57 * ccs_add_domain_acl - Add the given ACL to the given domain.
58 *
59 * @domain: Pointer to "struct ccs_domain_info". May be NULL.
60 * @acl: Pointer to "struct ccs_acl_info".
61 *
62 * Returns 0.
63 */
64 int ccs_add_domain_acl(struct ccs_domain_info *domain, struct ccs_acl_info *acl)
65 {
66 if (domain) {
67 if (acl->cond)
68 atomic_inc(&acl->cond->users);
69 list_add_tail_rcu(&acl->list, &domain->acl_info_list);
70 } else {
71 acl->type &= ~ACL_DELETED;
72 }
73 ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
74 return 0;
75 }
76
77 /**
78 * ccs_del_domain_acl - Delete the given ACL from the domain.
79 *
80 * @acl: Pointer to "struct ccs_acl_info". May be NULL.
81 *
82 * Returns 0.
83 */
84 int ccs_del_domain_acl(struct ccs_acl_info *acl)
85 {
86 if (acl)
87 acl->type |= ACL_DELETED;
88 ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
89 return 0;
90 }
91
92 /**
93 * ccs_audit_execute_handler_log - Audit execute_handler log.
94 *
95 * @ee: Pointer to "struct ccs_execve_entry".
96 * @is_default: True if it is "execute_handler" log.
97 *
98 * Returns 0 on success, negative value otherwise.
99 */
100 static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,
101 const bool is_default)
102 {
103 struct ccs_request_info *r = &ee->r;
104 const char *handler = ee->handler->name;
105 r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_FILE);
106 return ccs_write_audit_log(true, r, "%s %s\n",
107 is_default ? KEYWORD_EXECUTE_HANDLER :
108 KEYWORD_DENIED_EXECUTE_HANDLER, handler);
109 }
110
111 /**
112 * ccs_audit_domain_creation_log - Audit domain creation log.
113 *
114 * @domain: Pointer to "struct ccs_domain_info".
115 *
116 * Returns 0 on success, negative value otherwise.
117 */
118 static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)
119 {
120 int error;
121 struct ccs_request_info r;
122 ccs_init_request_info(&r, domain, CCS_MAC_FOR_FILE);
123 error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);
124 return error;
125 }
126
127 /* The list for "struct ccs_domain_initializer_entry". */
128 LIST_HEAD(ccs_domain_initializer_list);
129
130 /**
131 * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.
132 *
133 * @domainname: The name of domain. May be NULL.
134 * @program: The name of program.
135 * @is_not: True if it is "no_initialize_domain" entry.
136 * @is_delete: True if it is a delete request.
137 *
138 * Returns 0 on success, negative value otherwise.
139 */
140 static int ccs_update_domain_initializer_entry(const char *domainname,
141 const char *program,
142 const bool is_not,
143 const bool is_delete)
144 {
145 struct ccs_domain_initializer_entry *entry = NULL;
146 struct ccs_domain_initializer_entry *ptr;
147 const struct ccs_path_info *saved_program;
148 const struct ccs_path_info *saved_domainname = NULL;
149 int error = is_delete ? -ENOENT : -ENOMEM;
150 bool is_last_name = false;
151 if (!ccs_is_correct_path(program, 1, -1, -1))
152 return -EINVAL; /* No patterns allowed. */
153 if (domainname) {
154 if (!ccs_is_domain_def(domainname) &&
155 ccs_is_correct_path(domainname, 1, -1, -1))
156 is_last_name = true;
157 else if (!ccs_is_correct_domain(domainname))
158 return -EINVAL;
159 saved_domainname = ccs_get_name(domainname);
160 if (!saved_domainname)
161 return -ENOMEM;
162 }
163 saved_program = ccs_get_name(program);
164 if (!saved_program) {
165 ccs_put_name(saved_domainname);
166 return -ENOMEM;
167 }
168 if (!is_delete)
169 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
170 mutex_lock(&ccs_policy_lock);
171 list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
172 if (ptr->is_not != is_not ||
173 ptr->domainname != saved_domainname ||
174 ptr->program != saved_program)
175 continue;
176 ptr->is_deleted = is_delete;
177 error = 0;
178 break;
179 }
180 if (!is_delete && error && ccs_memory_ok(entry)) {
181 entry->domainname = saved_domainname;
182 saved_domainname = NULL;
183 entry->program = saved_program;
184 saved_program = NULL;
185 entry->is_not = is_not;
186 entry->is_last_name = is_last_name;
187 list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);
188 entry = NULL;
189 error = 0;
190 }
191 mutex_unlock(&ccs_policy_lock);
192 ccs_put_name(saved_domainname);
193 ccs_put_name(saved_program);
194 kfree(entry);
195 ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
196 return error;
197 }
198
199 /**
200 * ccs_read_domain_initializer_policy - Read "struct ccs_domain_initializer_entry" list.
201 *
202 * @head: Pointer to "struct ccs_io_buffer".
203 *
204 * Returns true on success, false otherwise.
205 *
206 * Caller holds srcu_read_lock(&ccs_ss).
207 */
208 bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
209 {
210 struct list_head *pos;
211 bool done = true;
212 list_for_each_cookie(pos, head->read_var2,
213 &ccs_domain_initializer_list) {
214 const char *no;
215 const char *from = "";
216 const char *domain = "";
217 struct ccs_domain_initializer_entry *ptr;
218 ptr = list_entry(pos, struct ccs_domain_initializer_entry,
219 list);
220 if (ptr->is_deleted)
221 continue;
222 no = ptr->is_not ? "no_" : "";
223 if (ptr->domainname) {
224 from = " from ";
225 domain = ptr->domainname->name;
226 }
227 done = ccs_io_printf(head,
228 "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",
229 no, ptr->program->name, from, domain);
230 if (!done)
231 break;
232 }
233 return done;
234 }
235
236 /**
237 * ccs_write_domain_initializer_policy - Write "struct ccs_domain_initializer_entry" list.
238 *
239 * @data: String to parse.
240 * @is_not: True if it is "no_initialize_domain" entry.
241 * @is_delete: True if it is a delete request.
242 *
243 * Returns 0 on success, negative value otherwise.
244 */
245 int ccs_write_domain_initializer_policy(char *data, const bool is_not,
246 const bool is_delete)
247 {
248 char *cp = strstr(data, " from ");
249 if (cp) {
250 *cp = '\0';
251 return ccs_update_domain_initializer_entry(cp + 6, data,
252 is_not, is_delete);
253 }
254 return ccs_update_domain_initializer_entry(NULL, data, is_not,
255 is_delete);
256 }
257
258 /**
259 * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.
260 *
261 * @domainname: The name of domain.
262 * @program: The name of program.
263 * @last_name: The last component of @domainname.
264 *
265 * Returns true if executing @program reinitializes domain transition,
266 * false otherwise.
267 *
268 * Caller holds srcu_read_lock(&ccs_ss).
269 */
270 static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,
271 const struct ccs_path_info *program,
272 const struct ccs_path_info *last_name)
273 {
274 struct ccs_domain_initializer_entry *ptr;
275 bool flag = false;
276 list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
277 if (ptr->is_deleted)
278 continue;
279 if (ptr->domainname) {
280 if (!ptr->is_last_name) {
281 if (ptr->domainname != domainname)
282 continue;
283 } else {
284 if (ccs_pathcmp(ptr->domainname, last_name))
285 continue;
286 }
287 }
288 if (ccs_pathcmp(ptr->program, program))
289 continue;
290 if (ptr->is_not) {
291 flag = false;
292 break;
293 }
294 flag = true;
295 }
296 return flag;
297 }
298
299 /* The list for "struct ccs_domain_keeper_entry". */
300 LIST_HEAD(ccs_domain_keeper_list);
301
302 /**
303 * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.
304 *
305 * @domainname: The name of domain.
306 * @program: The name of program. May be NULL.
307 * @is_not: True if it is "no_keep_domain" entry.
308 * @is_delete: True if it is a delete request.
309 *
310 * Returns 0 on success, negative value otherwise.
311 */
312 static int ccs_update_domain_keeper_entry(const char *domainname,
313 const char *program,
314 const bool is_not,
315 const bool is_delete)
316 {
317 struct ccs_domain_keeper_entry *entry = NULL;
318 struct ccs_domain_keeper_entry *ptr;
319 const struct ccs_path_info *saved_domainname;
320 const struct ccs_path_info *saved_program = NULL;
321 int error = is_delete ? -ENOENT : -ENOMEM;
322 bool is_last_name = false;
323 if (!ccs_is_domain_def(domainname) &&
324 ccs_is_correct_path(domainname, 1, -1, -1))
325 is_last_name = true;
326 else if (!ccs_is_correct_domain(domainname))
327 return -EINVAL;
328 if (program) {
329 if (!ccs_is_correct_path(program, 1, -1, -1))
330 return -EINVAL;
331 saved_program = ccs_get_name(program);
332 if (!saved_program)
333 return -ENOMEM;
334 }
335 saved_domainname = ccs_get_name(domainname);
336 if (!saved_domainname) {
337 ccs_put_name(saved_program);
338 return -ENOMEM;
339 }
340 if (!is_delete)
341 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
342 mutex_lock(&ccs_policy_lock);
343 list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
344 if (ptr->is_not != is_not ||
345 ptr->domainname != saved_domainname ||
346 ptr->program != saved_program)
347 continue;
348 ptr->is_deleted = is_delete;
349 error = 0;
350 break;
351 }
352 if (!is_delete && error && ccs_memory_ok(entry)) {
353 entry->domainname = saved_domainname;
354 saved_domainname = NULL;
355 entry->program = saved_program;
356 saved_program = NULL;
357 entry->is_not = is_not;
358 entry->is_last_name = is_last_name;
359 list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);
360 entry = NULL;
361 error = 0;
362 }
363 mutex_unlock(&ccs_policy_lock);
364 ccs_put_name(saved_domainname);
365 ccs_put_name(saved_program);
366 kfree(entry);
367 ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
368 return error;
369 }
370
371 /**
372 * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.
373 *
374 * @data: String to parse.
375 * @is_not: True if it is "no_keep_domain" entry.
376 * @is_delete: True if it is a delete request.
377 *
378 */
379 int ccs_write_domain_keeper_policy(char *data, const bool is_not,
380 const bool is_delete)
381 {
382 char *cp = strstr(data, " from ");
383 if (cp) {
384 *cp = '\0';
385 return ccs_update_domain_keeper_entry(cp + 6, data,
386 is_not, is_delete);
387 }
388 return ccs_update_domain_keeper_entry(data, NULL, is_not, is_delete);
389 }
390
391 /**
392 * ccs_read_domain_keeper_policy - Read "struct ccs_domain_keeper_entry" list.
393 *
394 * @head: Pointer to "struct ccs_io_buffer".
395 *
396 * Returns true on success, false otherwise.
397 *
398 * Caller holds srcu_read_lock(&ccs_ss).
399 */
400 bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
401 {
402 struct list_head *pos;
403 bool done = true;
404 list_for_each_cookie(pos, head->read_var2,
405 &ccs_domain_keeper_list) {
406 struct ccs_domain_keeper_entry *ptr;
407 const char *no;
408 const char *from = "";
409 const char *program = "";
410 ptr = list_entry(pos, struct ccs_domain_keeper_entry, list);
411 if (ptr->is_deleted)
412 continue;
413 no = ptr->is_not ? "no_" : "";
414 if (ptr->program) {
415 from = " from ";
416 program = ptr->program->name;
417 }
418 done = ccs_io_printf(head,
419 "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,
420 program, from, ptr->domainname->name);
421 if (!done)
422 break;
423 }
424 return done;
425 }
426
427 /**
428 * ccs_is_domain_keeper - Check whether the given program causes domain transition suppression.
429 *
430 * @domainname: The name of domain.
431 * @program: The name of program.
432 * @last_name: The last component of @domainname.
433 *
434 * Returns true if executing @program supresses domain transition,
435 * false otherwise.
436 *
437 * Caller holds srcu_read_lock(&ccs_ss).
438 */
439 static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,
440 const struct ccs_path_info *program,
441 const struct ccs_path_info *last_name)
442 {
443 struct ccs_domain_keeper_entry *ptr;
444 bool flag = false;
445 list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
446 if (ptr->is_deleted)
447 continue;
448 if (!ptr->is_last_name) {
449 if (ptr->domainname != domainname)
450 continue;
451 } else {
452 if (ccs_pathcmp(ptr->domainname, last_name))
453 continue;
454 }
455 if (ptr->program && ccs_pathcmp(ptr->program, program))
456 continue;
457 if (ptr->is_not) {
458 flag = false;
459 break;
460 }
461 flag = true;
462 }
463 return flag;
464 }
465
466 /* The list for "struct ccs_alias_entry". */
467 LIST_HEAD(ccs_alias_list);
468
469 /**
470 * ccs_update_alias_entry - Update "struct ccs_alias_entry" list.
471 *
472 * @original_name: The original program's real name.
473 * @aliased_name: The symbolic program's symbolic link's name.
474 * @is_delete: True if it is a delete request.
475 *
476 * Returns 0 on success, negative value otherwise.
477 */
478 static int ccs_update_alias_entry(const char *original_name,
479 const char *aliased_name,
480 const bool is_delete)
481 {
482 struct ccs_alias_entry *entry = NULL;
483 struct ccs_alias_entry *ptr;
484 const struct ccs_path_info *saved_original_name;
485 const struct ccs_path_info *saved_aliased_name;
486 int error = is_delete ? -ENOENT : -ENOMEM;
487 if (!ccs_is_correct_path(original_name, 1, -1, -1) ||
488 !ccs_is_correct_path(aliased_name, 1, -1, -1))
489 return -EINVAL; /* No patterns allowed. */
490 saved_original_name = ccs_get_name(original_name);
491 saved_aliased_name = ccs_get_name(aliased_name);
492 if (!saved_original_name || !saved_aliased_name) {
493 ccs_put_name(saved_original_name);
494 ccs_put_name(saved_aliased_name);
495 return -ENOMEM;
496 }
497 if (!is_delete)
498 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
499 mutex_lock(&ccs_policy_lock);
500 list_for_each_entry_rcu(ptr, &ccs_alias_list, list) {
501 if (ptr->original_name != saved_original_name ||
502 ptr->aliased_name != saved_aliased_name)
503 continue;
504 ptr->is_deleted = is_delete;
505 error = 0;
506 break;
507 }
508 if (!is_delete && error && ccs_memory_ok(entry)) {
509 entry->original_name = saved_original_name;
510 saved_original_name = NULL;
511 entry->aliased_name = saved_aliased_name;
512 saved_aliased_name = NULL;
513 list_add_tail_rcu(&entry->list, &ccs_alias_list);
514 entry = NULL;
515 error = 0;
516 }
517 mutex_unlock(&ccs_policy_lock);
518 ccs_put_name(saved_original_name);
519 ccs_put_name(saved_aliased_name);
520 kfree(entry);
521 ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
522 return error;
523 }
524
525 /**
526 * ccs_read_alias_policy - Read "struct ccs_alias_entry" list.
527 *
528 * @head: Pointer to "struct ccs_io_buffer".
529 *
530 * Returns true on success, false otherwise.
531 *
532 * Caller holds srcu_read_lock(&ccs_ss).
533 */
534 bool ccs_read_alias_policy(struct ccs_io_buffer *head)
535 {
536 struct list_head *pos;
537 bool done = true;
538 list_for_each_cookie(pos, head->read_var2, &ccs_alias_list) {
539 struct ccs_alias_entry *ptr;
540 ptr = list_entry(pos, struct ccs_alias_entry, list);
541 if (ptr->is_deleted)
542 continue;
543 done = ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",
544 ptr->original_name->name,
545 ptr->aliased_name->name);
546 if (!done)
547 break;
548 }
549 return done;
550 }
551
552 /**
553 * ccs_write_alias_policy - Write "struct ccs_alias_entry" list.
554 *
555 * @data: String to parse.
556 * @is_delete: True if it is a delete request.
557 *
558 * Returns 0 on success, negative value otherwise.
559 */
560 int ccs_write_alias_policy(char *data, const bool is_delete)
561 {
562 char *cp = strchr(data, ' ');
563 if (!cp)
564 return -EINVAL;
565 *cp++ = '\0';
566 return ccs_update_alias_entry(data, cp, is_delete);
567 }
568
569 /* The list for "struct ccs_aggregator_entry". */
570 LIST_HEAD(ccs_aggregator_list);
571
572 /**
573 * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.
574 *
575 * @original_name: The original program's name.
576 * @aggregated_name: The aggregated program's name.
577 * @is_delete: True if it is a delete request.
578 *
579 * Returns 0 on success, negative value otherwise.
580 */
581 static int ccs_update_aggregator_entry(const char *original_name,
582 const char *aggregated_name,
583 const bool is_delete)
584 {
585 struct ccs_aggregator_entry *entry = NULL;
586 struct ccs_aggregator_entry *ptr;
587 const struct ccs_path_info *saved_original_name;
588 const struct ccs_path_info *saved_aggregated_name;
589 int error = is_delete ? -ENOENT : -ENOMEM;
590 if (!ccs_is_correct_path(original_name, 1, 0, -1) ||
591 !ccs_is_correct_path(aggregated_name, 1, -1, -1))
592 return -EINVAL;
593 saved_original_name = ccs_get_name(original_name);
594 saved_aggregated_name = ccs_get_name(aggregated_name);
595 if (!saved_original_name || !saved_aggregated_name) {
596 ccs_put_name(saved_original_name);
597 ccs_put_name(saved_aggregated_name);
598 return -ENOMEM;
599 }
600 if (!is_delete)
601 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
602 mutex_lock(&ccs_policy_lock);
603 list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
604 if (ptr->original_name != saved_original_name ||
605 ptr->aggregated_name != saved_aggregated_name)
606 continue;
607 ptr->is_deleted = is_delete;
608 error = 0;
609 break;
610 }
611 if (!is_delete && error && ccs_memory_ok(entry)) {
612 entry->original_name = saved_original_name;
613 saved_original_name = NULL;
614 entry->aggregated_name = saved_aggregated_name;
615 saved_aggregated_name = NULL;
616 list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
617 entry = NULL;
618 error = 0;
619 }
620 mutex_unlock(&ccs_policy_lock);
621 ccs_put_name(saved_original_name);
622 ccs_put_name(saved_aggregated_name);
623 kfree(entry);
624 ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
625 return error;
626 }
627
628 /**
629 * ccs_read_aggregator_policy - Read "struct ccs_aggregator_entry" list.
630 *
631 * @head: Pointer to "struct ccs_io_buffer".
632 *
633 * Returns true on success, false otherwise.
634 *
635 * Caller holds srcu_read_lock(&ccs_ss).
636 */
637 bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
638 {
639 struct list_head *pos;
640 bool done = true;
641 list_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {
642 struct ccs_aggregator_entry *ptr;
643 ptr = list_entry(pos, struct ccs_aggregator_entry, list);
644 if (ptr->is_deleted)
645 continue;
646 done = ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",
647 ptr->original_name->name,
648 ptr->aggregated_name->name);
649 if (!done)
650 break;
651 }
652 return done;
653 }
654
655 /**
656 * ccs_write_aggregator_policy - Write "struct ccs_aggregator_entry" list.
657 *
658 * @data: String to parse.
659 * @is_delete: True if it is a delete request.
660 *
661 * Returns 0 on success, negative value otherwise.
662 */
663 int ccs_write_aggregator_policy(char *data, const bool is_delete)
664 {
665 char *cp = strchr(data, ' ');
666 if (!cp)
667 return -EINVAL;
668 *cp++ = '\0';
669 return ccs_update_aggregator_entry(data, cp, is_delete);
670 }
671
672 /* Domain create/delete handler. */
673
674 /**
675 * ccs_delete_domain - Delete a domain.
676 *
677 * @domainname: The name of domain.
678 *
679 * Returns 0.
680 */
681 int ccs_delete_domain(char *domainname)
682 {
683 struct ccs_domain_info *domain;
684 struct ccs_path_info name;
685 name.name = domainname;
686 ccs_fill_path_info(&name);
687 mutex_lock(&ccs_policy_lock);
688 /* Is there an active domain? */
689 list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
690 /* Never delete ccs_kernel_domain */
691 if (domain == &ccs_kernel_domain)
692 continue;
693 if (domain->is_deleted ||
694 ccs_pathcmp(domain->domainname, &name))
695 continue;
696 domain->is_deleted = true;
697 break;
698 }
699 mutex_unlock(&ccs_policy_lock);
700 return 0;
701 }
702
703 /**
704 * ccs_find_or_assign_new_domain - Create a domain.
705 *
706 * @domainname: The name of domain.
707 * @profile: Profile number to assign if the domain was newly created.
708 *
709 * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
710 */
711 struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,
712 const u8 profile)
713 {
714 struct ccs_domain_info *entry;
715 struct ccs_domain_info *domain;
716 const struct ccs_path_info *saved_domainname;
717 bool found = false;
718
719 if (!ccs_is_correct_domain(domainname))
720 return NULL;
721 saved_domainname = ccs_get_name(domainname);
722 if (!saved_domainname)
723 return NULL;
724 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
725 mutex_lock(&ccs_policy_lock);
726 list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
727 if (domain->is_deleted ||
728 ccs_pathcmp(saved_domainname, domain->domainname))
729 continue;
730 found = true;
731 break;
732 }
733 if (!found && ccs_memory_ok(entry)) {
734 INIT_LIST_HEAD(&entry->acl_info_list);
735 entry->domainname = saved_domainname;
736 saved_domainname = NULL;
737 entry->profile = profile;
738 list_add_tail_rcu(&entry->list, &ccs_domain_list);
739 domain = entry;
740 entry = NULL;
741 found = true;
742 }
743 mutex_unlock(&ccs_policy_lock);
744 ccs_put_name(saved_domainname);
745 kfree(entry);
746 return found ? domain : NULL;
747 }
748
749 /**
750 * ccs_get_argv0 - Get argv[0].
751 *
752 * @ee: Pointer to "struct ccs_execve_entry".
753 *
754 * Returns true on success, false otherwise.
755 */
756 static bool ccs_get_argv0(struct ccs_execve_entry *ee)
757 {
758 struct linux_binprm *bprm = ee->bprm;
759 char *arg_ptr = ee->tmp;
760 int arg_len = 0;
761 unsigned long pos = bprm->p;
762 int offset = pos % PAGE_SIZE;
763 bool done = false;
764 if (!bprm->argc)
765 goto out;
766 while (1) {
767 if (!ccs_dump_page(bprm, pos, &ee->dump))
768 goto out;
769 pos += PAGE_SIZE - offset;
770 /* Read. */
771 while (offset < PAGE_SIZE) {
772 const char *kaddr = ee->dump.data;
773 const unsigned char c = kaddr[offset++];
774 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
775 if (c == '\\') {
776 arg_ptr[arg_len++] = '\\';
777 arg_ptr[arg_len++] = '\\';
778 } else if (c == '/') {
779 arg_len = 0;
780 } else if (c > ' ' && c < 127) {
781 arg_ptr[arg_len++] = c;
782 } else {
783 arg_ptr[arg_len++] = '\\';
784 arg_ptr[arg_len++] = (c >> 6) + '0';
785 arg_ptr[arg_len++]
786 = ((c >> 3) & 7) + '0';
787 arg_ptr[arg_len++] = (c & 7) + '0';
788 }
789 } else {
790 arg_ptr[arg_len] = '\0';
791 done = true;
792 break;
793 }
794 }
795 offset = 0;
796 if (done)
797 break;
798 }
799 return true;
800 out:
801 return false;
802 }
803
804 /**
805 * ccs_find_next_domain - Find a domain.
806 *
807 * @ee: Pointer to "struct ccs_execve_entry".
808 *
809 * Returns 0 on success, negative value otherwise.
810 *
811 * Caller holds srcu_read_lock(&ccs_ss).
812 */
813 static int ccs_find_next_domain(struct ccs_execve_entry *ee)
814 {
815 struct ccs_request_info *r = &ee->r;
816 const struct ccs_path_info *handler = ee->handler;
817 struct ccs_domain_info *domain = NULL;
818 const char *old_domain_name = r->domain->domainname->name;
819 struct linux_binprm *bprm = ee->bprm;
820 const u8 mode = r->mode;
821 const bool is_enforce = (mode == 3);
822 const u32 ccs_flags = current->ccs_flags;
823 char *new_domain_name = NULL;
824 struct ccs_path_info rn; /* real name */
825 struct ccs_path_info sn; /* symlink name */
826 struct ccs_path_info ln; /* last name */
827 int retval;
828 retry:
829 current->ccs_flags = ccs_flags;
830 r->cond = NULL;
831 /* Get realpath of program and symbolic link. */
832 retval = ccs_realpath_both(bprm->filename, ee);
833 if (retval < 0)
834 goto out;
835
836 rn.name = ee->program_path;
837 ccs_fill_path_info(&rn);
838 sn.name = ee->tmp;
839 ccs_fill_path_info(&sn);
840 ln.name = ccs_get_last_name(r->domain);
841 ccs_fill_path_info(&ln);
842
843 if (handler) {
844 if (ccs_pathcmp(&rn, handler)) {
845 /* Failed to verify execute handler. */
846 static u8 counter = 20;
847 if (counter) {
848 counter--;
849 printk(KERN_WARNING "Failed to verify: %s\n",
850 handler->name);
851 }
852 goto out;
853 }
854 goto calculate_domain;
855 }
856
857 /* Check 'alias' directive. */
858 if (ccs_pathcmp(&rn, &sn)) {
859 struct ccs_alias_entry *ptr;
860 /* Is this program allowed to be called via symbolic links? */
861 list_for_each_entry_rcu(ptr, &ccs_alias_list, list) {
862 if (ptr->is_deleted ||
863 ccs_pathcmp(&rn, ptr->original_name) ||
864 ccs_pathcmp(&sn, ptr->aliased_name))
865 continue;
866 strncpy(ee->program_path, ptr->aliased_name->name,
867 CCS_MAX_PATHNAME_LEN - 1);
868 ccs_fill_path_info(&rn);
869 break;
870 }
871 }
872 /* sn will be overwritten after here. */
873
874 /* Compare basename of program_path and argv[0] */
875 r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_ARGV0);
876 if (bprm->argc > 0 && r->mode) {
877 char *base_argv0 = ee->tmp;
878 const char *base_filename;
879 retval = -ENOMEM;
880 if (!ccs_get_argv0(ee))
881 goto out;
882 base_filename = strrchr(ee->program_path, '/');
883 if (!base_filename)
884 base_filename = ee->program_path;
885 else
886 base_filename++;
887 if (strcmp(base_argv0, base_filename)) {
888 retval = ccs_check_argv0_perm(r, &rn, base_argv0);
889 if (retval == 1)
890 goto retry;
891 if (retval < 0)
892 goto out;
893 }
894 }
895
896 /* Check 'aggregator' directive. */
897 {
898 struct ccs_aggregator_entry *ptr;
899 /* Is this program allowed to be aggregated? */
900 list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
901 if (ptr->is_deleted ||
902 !ccs_path_matches_pattern(&rn, ptr->original_name))
903 continue;
904 strncpy(ee->program_path, ptr->aggregated_name->name,
905 CCS_MAX_PATHNAME_LEN - 1);
906 ccs_fill_path_info(&rn);
907 break;
908 }
909 }
910
911 /* Check execute permission. */
912 r->mode = mode;
913 retval = ccs_check_exec_perm(r, &rn);
914 if (retval == 1)
915 goto retry;
916 if (retval < 0)
917 goto out;
918
919 calculate_domain:
920 new_domain_name = ee->tmp;
921 if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
922 /* Transit to the child of ccs_kernel_domain domain. */
923 snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
924 ROOT_NAME " " "%s", ee->program_path);
925 } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
926 /*
927 * Needn't to transit from kernel domain before starting
928 * /sbin/init. But transit from kernel domain if executing
929 * initializers because they might start before /sbin/init.
930 */
931 domain = r->domain;
932 } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {
933 /* Keep current domain. */
934 domain = r->domain;
935 } else {
936 /* Normal domain transition. */
937 snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
938 "%s %s", old_domain_name, ee->program_path);
939 }
940 if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
941 goto done;
942 domain = ccs_find_domain(new_domain_name);
943 if (domain)
944 goto done;
945 if (is_enforce) {
946 int error = ccs_check_supervisor(r,
947 "# wants to create domain\n"
948 "%s\n", new_domain_name);
949 if (error == 1)
950 goto retry;
951 if (error < 0)
952 goto done;
953 }
954 domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);
955 if (domain)
956 ccs_audit_domain_creation_log(r->domain);
957 done:
958 if (!domain) {
959 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
960 new_domain_name);
961 if (is_enforce)
962 retval = -EPERM;
963 else {
964 retval = 0;
965 r->domain->domain_transition_failed = true;
966 }
967 } else {
968 retval = 0;
969 }
970 out:
971 if (domain)
972 r->domain = domain;
973 return retval;
974 }
975
976 /**
977 * ccs_check_environ - Check permission for environment variable names.
978 *
979 * @ee: Pointer to "struct ccs_execve_entry".
980 *
981 * Returns 0 on success, negative value otherwise.
982 */
983 static int ccs_check_environ(struct ccs_execve_entry *ee)
984 {
985 struct ccs_request_info *r = &ee->r;
986 struct linux_binprm *bprm = ee->bprm;
987 char *arg_ptr = ee->tmp;
988 int arg_len = 0;
989 unsigned long pos = bprm->p;
990 int offset = pos % PAGE_SIZE;
991 int argv_count = bprm->argc;
992 int envp_count = bprm->envc;
993 /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
994 int error = -ENOMEM;
995 if (!r->mode || !envp_count)
996 return 0;
997 while (error == -ENOMEM) {
998 if (!ccs_dump_page(bprm, pos, &ee->dump))
999 goto out;
1000 pos += PAGE_SIZE - offset;
1001 /* Read. */
1002 while (argv_count && offset < PAGE_SIZE) {
1003 const char *kaddr = ee->dump.data;
1004 if (!kaddr[offset++])
1005 argv_count--;
1006 }
1007 if (argv_count) {
1008 offset = 0;
1009 continue;
1010 }
1011 while (offset < PAGE_SIZE) {
1012 const char *kaddr = ee->dump.data;
1013 const unsigned char c = kaddr[offset++];
1014 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1015 if (c == '=') {
1016 arg_ptr[arg_len++] = '\0';
1017 } else if (c == '\\') {
1018 arg_ptr[arg_len++] = '\\';
1019 arg_ptr[arg_len++] = '\\';
1020 } else if (c > ' ' && c < 127) {
1021 arg_ptr[arg_len++] = c;
1022 } else {
1023 arg_ptr[arg_len++] = '\\';
1024 arg_ptr[arg_len++] = (c >> 6) + '0';
1025 arg_ptr[arg_len++]
1026 = ((c >> 3) & 7) + '0';
1027 arg_ptr[arg_len++] = (c & 7) + '0';
1028 }
1029 } else {
1030 arg_ptr[arg_len] = '\0';
1031 }
1032 if (c)
1033 continue;
1034 if (ccs_check_env_perm(r, arg_ptr)) {
1035 error = -EPERM;
1036 break;
1037 }
1038 if (!--envp_count) {
1039 error = 0;
1040 break;
1041 }
1042 arg_len = 0;
1043 }
1044 offset = 0;
1045 }
1046 out:
1047 if (r->mode != 3)
1048 error = 0;
1049 return error;
1050 }
1051
1052 /**
1053 * ccs_unescape - Unescape escaped string.
1054 *
1055 * @dest: String to unescape.
1056 *
1057 * Returns nothing.
1058 */
1059 static void ccs_unescape(unsigned char *dest)
1060 {
1061 unsigned char *src = dest;
1062 unsigned char c;
1063 unsigned char d;
1064 unsigned char e;
1065 while (1) {
1066 c = *src++;
1067 if (!c)
1068 break;
1069 if (c != '\\') {
1070 *dest++ = c;
1071 continue;
1072 }
1073 c = *src++;
1074 if (c == '\\') {
1075 *dest++ = c;
1076 continue;
1077 }
1078 if (c < '0' || c > '3')
1079 break;
1080 d = *src++;
1081 if (d < '0' || d > '7')
1082 break;
1083 e = *src++;
1084 if (e < '0' || e > '7')
1085 break;
1086 *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1087 }
1088 *dest = '\0';
1089 }
1090
1091 /**
1092 * ccs_root_depth - Get number of directories to strip.
1093 *
1094 * @dentry: Pointer to "struct dentry".
1095 * @vfsmnt: Pointer to "struct vfsmount".
1096 *
1097 * Returns number of directories to strip.
1098 */
1099 static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1100 {
1101 int depth = 0;
1102 /***** CRITICAL SECTION START *****/
1103 ccs_realpath_lock();
1104 for (;;) {
1105 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1106 /* Global root? */
1107 if (vfsmnt->mnt_parent == vfsmnt)
1108 break;
1109 dentry = vfsmnt->mnt_mountpoint;
1110 vfsmnt = vfsmnt->mnt_parent;
1111 continue;
1112 }
1113 dentry = dentry->d_parent;
1114 depth++;
1115 }
1116 ccs_realpath_unlock();
1117 /***** CRITICAL SECTION END *****/
1118 return depth;
1119 }
1120
1121 /**
1122 * ccs_get_root_depth - return the depth of root directory.
1123 *
1124 * Returns number of directories to strip.
1125 */
1126 static int ccs_get_root_depth(void)
1127 {
1128 int depth;
1129 struct dentry *dentry;
1130 struct vfsmount *vfsmnt;
1131 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1132 struct path root;
1133 #endif
1134 /***** CRITICAL SECTION START *****/
1135 read_lock(&current->fs->lock);
1136 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1137 root = current->fs->root;
1138 path_get(&current->fs->root);
1139 dentry = root.dentry;
1140 vfsmnt = root.mnt;
1141 #else
1142 dentry = dget(current->fs->root);
1143 vfsmnt = mntget(current->fs->rootmnt);
1144 #endif
1145 read_unlock(&current->fs->lock);
1146 /***** CRITICAL SECTION END *****/
1147 depth = ccs_root_depth(dentry, vfsmnt);
1148 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1149 path_put(&root);
1150 #else
1151 dput(dentry);
1152 mntput(vfsmnt);
1153 #endif
1154 return depth;
1155 }
1156
1157 static LIST_HEAD(ccs_execve_list);
1158 static DEFINE_SPINLOCK(ccs_execve_list_lock);
1159
1160 /**
1161 * ccs_allocate_execve_entry - Allocate memory for execve().
1162 *
1163 * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1164 */
1165 static struct ccs_execve_entry *ccs_allocate_execve_entry(void)
1166 {
1167 struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);
1168 if (!ee)
1169 return NULL;
1170 memset(ee, 0, sizeof(*ee));
1171 ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1172 ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1173 if (!ee->program_path || !ee->tmp) {
1174 ccs_free(ee->program_path);
1175 ccs_free(ee->tmp);
1176 ccs_free(ee);
1177 return NULL;
1178 }
1179 ee->srcu_idx = srcu_read_lock(&ccs_ss);
1180 /* ee->dump->data is allocated by ccs_dump_page(). */
1181 ee->task = current;
1182 /***** CRITICAL SECTION START *****/
1183 spin_lock(&ccs_execve_list_lock);
1184 list_add(&ee->list, &ccs_execve_list);
1185 spin_unlock(&ccs_execve_list_lock);
1186 /***** CRITICAL SECTION END *****/
1187 return ee;
1188 }
1189
1190 /**
1191 * ccs_find_execve_entry - Find ccs_execve_entry of current process.
1192 *
1193 * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1194 */
1195 static struct ccs_execve_entry *ccs_find_execve_entry(void)
1196 {
1197 struct task_struct *task = current;
1198 struct ccs_execve_entry *ee = NULL;
1199 struct ccs_execve_entry *p;
1200 /***** CRITICAL SECTION START *****/
1201 spin_lock(&ccs_execve_list_lock);
1202 list_for_each_entry(p, &ccs_execve_list, list) {
1203 if (p->task != task)
1204 continue;
1205 ee = p;
1206 break;
1207 }
1208 spin_unlock(&ccs_execve_list_lock);
1209 /***** CRITICAL SECTION END *****/
1210 return ee;
1211 }
1212
1213 /**
1214 * ccs_free_execve_entry - Free memory for execve().
1215 *
1216 * @ee: Pointer to "struct ccs_execve_entry".
1217 */
1218 static void ccs_free_execve_entry(struct ccs_execve_entry *ee)
1219 {
1220 if (!ee)
1221 return;
1222 /***** CRITICAL SECTION START *****/
1223 spin_lock(&ccs_execve_list_lock);
1224 list_del(&ee->list);
1225 spin_unlock(&ccs_execve_list_lock);
1226 /***** CRITICAL SECTION END *****/
1227 ccs_free(ee->program_path);
1228 ccs_free(ee->tmp);
1229 kfree(ee->dump.data);
1230 srcu_read_unlock(&ccs_ss, ee->srcu_idx);
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 }

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