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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2854 - (show annotations) (download) (as text)
Wed Aug 5 11:57:20 2009 UTC (14 years, 10 months ago) by kumaneko
Original Path: branches/ccs-patch/fs/ccsecurity/domain.c
File MIME type: text/x-csrc
File size: 39416 byte(s)


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

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