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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2864 - (show annotations) (download) (as text)
Fri Aug 7 06:40:37 2009 UTC (14 years, 9 months ago) by kumaneko
Original Path: branches/ccs-patch/security/ccsecurity/domain.c
File MIME type: text/x-csrc
File size: 39392 byte(s)


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

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