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

Subversion リポジトリの参照

Contents of /branches/ccs-patch/fs/tomoyo_domain.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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