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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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