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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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