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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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