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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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