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

Subversion リポジトリの参照

Contents of /trunk/1.5.x/ccs-patch/fs/tomoyo_domain.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 898 - (show annotations) (download) (as text)
Tue Jan 15 04:44:35 2008 UTC (16 years, 3 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 24653 byte(s)


1 /*
2 * fs/tomoyo_domain.c
3 *
4 * Implementation of the Domain-Based Mandatory Access Control.
5 *
6 * Copyright (C) 2005-2008 NTT DATA CORPORATION
7 *
8 * Version: 1.5.3-pre 2008/01/15
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 /***** TOMOYO Linux start. *****/
15
16 #include <linux/ccs_common.h>
17 #include <linux/tomoyo.h>
18 #include <linux/realpath.h>
19 #include <linux/highmem.h>
20 #include <linux/binfmts.h>
21
22 #ifndef for_each_process
23 #define for_each_process for_each_task
24 #endif
25
26 /************************* VARIABLES *************************/
27
28 /* The initial domain. */
29 struct domain_info KERNEL_DOMAIN = { NULL, NULL, NULL, 0, 0, 0 };
30
31 /* /sbin/init started? */
32 extern int sbin_init_started;
33
34 #ifdef CONFIG_TOMOYO
35
36 /* Lock for appending domain's ACL. */
37 DECLARE_MUTEX(domain_acl_lock);
38
39 /************************* UTILITY FUNCTIONS *************************/
40
41 /***** The structure for program files to force domain reconstruction. *****/
42
43 struct domain_initializer_entry {
44 struct domain_initializer_entry *next;
45 const struct path_info *domainname; /* This may be NULL */
46 const struct path_info *program;
47 u8 is_deleted;
48 u8 is_not;
49 u8 is_last_name;
50 };
51
52 /***** The structure for domains to not to transit domains. *****/
53
54 struct domain_keeper_entry {
55 struct domain_keeper_entry *next;
56 const struct path_info *domainname;
57 const struct path_info *program; /* This may be NULL */
58 u8 is_deleted;
59 u8 is_not;
60 u8 is_last_name;
61 };
62
63 /***** The structure for program files that should be aggregated. *****/
64
65 struct aggregator_entry {
66 struct aggregator_entry *next;
67 const struct path_info *original_name;
68 const struct path_info *aggregated_name;
69 int is_deleted;
70 };
71
72 /***** The structure for program files that should be aliased. *****/
73
74 struct alias_entry {
75 struct alias_entry *next;
76 const struct path_info *original_name;
77 const struct path_info *aliased_name;
78 int is_deleted;
79 };
80
81 /************************* VARIABLES *************************/
82
83 /* Domain creation lock. */
84 static DECLARE_MUTEX(new_domain_assign_lock);
85
86 /************************* UTILITY FUNCTIONS *************************/
87
88 const char *GetLastName(const struct domain_info *domain)
89 {
90 const char *cp0 = domain->domainname->name, *cp1;
91 if ((cp1 = strrchr(cp0, ' ')) != NULL) return cp1 + 1;
92 return cp0;
93 }
94
95 int AddDomainACL(struct acl_info *ptr, struct domain_info *domain, struct acl_info *new_ptr)
96 {
97 mb(); /* Avoid out-of-order execution. */
98 if (!ptr) domain->first_acl_ptr = (struct acl_info *) new_ptr;
99 else ptr->next = (struct acl_info *) new_ptr;
100 UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
101 return 0;
102 }
103
104 int DelDomainACL(struct acl_info *ptr)
105 {
106 ptr->is_deleted = 1;
107 UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
108 return 0;
109 }
110
111 /************************* DOMAIN INITIALIZER HANDLER *************************/
112
113 static struct domain_initializer_entry *domain_initializer_list = NULL;
114
115 static int AddDomainInitializerEntry(const char *domainname, const char *program, const int is_not, const int is_delete)
116 {
117 struct domain_initializer_entry *new_entry, *ptr;
118 static DECLARE_MUTEX(lock);
119 const struct path_info *saved_program, *saved_domainname = NULL;
120 int error = -ENOMEM;
121 int is_last_name = 0;
122 if (!IsCorrectPath(program, 1, -1, -1, __FUNCTION__)) return -EINVAL; /* No patterns allowed. */
123 if (domainname) {
124 if (!IsDomainDef(domainname) && IsCorrectPath(domainname, 1, -1, -1, __FUNCTION__)) {
125 is_last_name = 1;
126 } else if (!IsCorrectDomain(domainname, __FUNCTION__)) {
127 return -EINVAL;
128 }
129 if ((saved_domainname = SaveName(domainname)) == NULL) return -ENOMEM;
130 }
131 if ((saved_program = SaveName(program)) == NULL) return -ENOMEM;
132 down(&lock);
133 for (ptr = domain_initializer_list; ptr; ptr = ptr->next) {
134 if (ptr->is_not == is_not && ptr->domainname == saved_domainname && ptr->program == saved_program) {
135 ptr->is_deleted = is_delete;
136 error = 0;
137 goto out;
138 }
139 }
140 if (is_delete) {
141 error = -ENOENT;
142 goto out;
143 }
144 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
145 new_entry->domainname = saved_domainname;
146 new_entry->program = saved_program;
147 new_entry->is_not = is_not;
148 new_entry->is_last_name = is_last_name;
149 mb(); /* Avoid out-of-order execution. */
150 if ((ptr = domain_initializer_list) != NULL) {
151 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;
152 } else {
153 domain_initializer_list = new_entry;
154 }
155 error = 0;
156 out:
157 up(&lock);
158 return error;
159 }
160
161 int ReadDomainInitializerPolicy(struct io_buffer *head)
162 {
163 struct domain_initializer_entry *ptr = head->read_var2;
164 if (!ptr) ptr = domain_initializer_list;
165 while (ptr) {
166 head->read_var2 = ptr;
167 if (!ptr->is_deleted) {
168 if (ptr->domainname) {
169 if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s from %s\n", ptr->is_not ? "no_" : "", ptr->program->name, ptr->domainname->name)) break;
170 } else {
171 if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s\n", ptr->is_not ? "no_" : "", ptr->program->name)) break;
172 }
173 }
174 ptr = ptr->next;
175 }
176 return ptr ? -ENOMEM : 0;
177 }
178
179 int AddDomainInitializerPolicy(char *data, const int is_not, const int is_delete)
180 {
181 char *cp = strstr(data, " from ");
182 if (cp) {
183 *cp = '\0';
184 return AddDomainInitializerEntry(cp + 6, data, is_not, is_delete);
185 } else {
186 return AddDomainInitializerEntry(NULL, data, is_not, is_delete);
187 }
188 }
189
190 static int IsDomainInitializer(const struct path_info *domainname, const struct path_info *program, const struct path_info *last_name)
191 {
192 struct domain_initializer_entry *ptr;
193 int flag = 0;
194 for (ptr = domain_initializer_list; ptr; ptr = ptr->next) {
195 if (ptr->is_deleted ) continue;
196 if (ptr->domainname) {
197 if (!ptr->is_last_name) {
198 if (ptr->domainname != domainname) continue;
199 } else {
200 if (pathcmp(ptr->domainname, last_name)) continue;
201 }
202 }
203 if (pathcmp(ptr->program, program)) continue;
204 if (ptr->is_not) return 0;
205 flag = 1;
206 }
207 return flag;
208 }
209
210 /************************* DOMAIN KEEPER HANDLER *************************/
211
212 static struct domain_keeper_entry *domain_keeper_list = NULL;
213
214 static int AddDomainKeeperEntry(const char *domainname, const char *program, const int is_not, const int is_delete)
215 {
216 struct domain_keeper_entry *new_entry, *ptr;
217 const struct path_info *saved_domainname, *saved_program = NULL;
218 static DECLARE_MUTEX(lock);
219 int error = -ENOMEM;
220 int is_last_name = 0;
221 if (!IsDomainDef(domainname) && IsCorrectPath(domainname, 1, -1, -1, __FUNCTION__)) {
222 is_last_name = 1;
223 } else if (!IsCorrectDomain(domainname, __FUNCTION__)) {
224 return -EINVAL;
225 }
226 if (program) {
227 if (!IsCorrectPath(program, 1, -1, -1, __FUNCTION__)) return -EINVAL;
228 if ((saved_program = SaveName(program)) == NULL) return -ENOMEM;
229 }
230 if ((saved_domainname = SaveName(domainname)) == NULL) return -ENOMEM;
231 down(&lock);
232 for (ptr = domain_keeper_list; ptr; ptr = ptr->next) {
233 if (ptr->is_not == is_not && ptr->domainname == saved_domainname && ptr->program == saved_program) {
234 ptr->is_deleted = is_delete;
235 error = 0;
236 goto out;
237 }
238 }
239 if (is_delete) {
240 error = -ENOENT;
241 goto out;
242 }
243 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
244 new_entry->domainname = saved_domainname;
245 new_entry->program = saved_program;
246 new_entry->is_not = is_not;
247 new_entry->is_last_name = is_last_name;
248 mb(); /* Avoid out-of-order execution. */
249 if ((ptr = domain_keeper_list) != NULL) {
250 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;
251 } else {
252 domain_keeper_list = new_entry;
253 }
254 error = 0;
255 out:
256 up(&lock);
257 return error;
258 }
259
260 int AddDomainKeeperPolicy(char *data, const int is_not, const int is_delete)
261 {
262 char *cp = strstr(data, " from ");
263 if (cp) {
264 *cp = '\0';
265 return AddDomainKeeperEntry(cp + 6, data, is_not, is_delete);
266 } else {
267 return AddDomainKeeperEntry(data, NULL, is_not, is_delete);
268 }
269 }
270
271 int ReadDomainKeeperPolicy(struct io_buffer *head)
272 {
273 struct domain_keeper_entry *ptr = head->read_var2;
274 if (!ptr) ptr = domain_keeper_list;
275 while (ptr) {
276 head->read_var2 = ptr;
277 if (!ptr->is_deleted) {
278 if (ptr->program) {
279 if (io_printf(head, "%s" KEYWORD_KEEP_DOMAIN "%s from %s\n", ptr->is_not ? "no_" : "", ptr->program->name, ptr->domainname->name)) break;
280 } else {
281 if (io_printf(head, "%s" KEYWORD_KEEP_DOMAIN "%s\n", ptr->is_not ? "no_" : "", ptr->domainname->name)) break;
282 }
283 }
284 ptr = ptr->next;
285 }
286 return ptr ? -ENOMEM : 0;
287 }
288
289 static int IsDomainKeeper(const struct path_info *domainname, const struct path_info *program, const struct path_info *last_name)
290 {
291 struct domain_keeper_entry *ptr;
292 int flag = 0;
293 for (ptr = domain_keeper_list; ptr; ptr = ptr->next) {
294 if (ptr->is_deleted) continue;
295 if (!ptr->is_last_name) {
296 if (ptr->domainname != domainname) continue;
297 } else {
298 if (pathcmp(ptr->domainname, last_name)) continue;
299 }
300 if (ptr->program && pathcmp(ptr->program, program)) continue;
301 if (ptr->is_not) return 0;
302 flag = 1;
303 }
304 return flag;
305 }
306
307 /************************* SYMBOLIC LINKED PROGRAM HANDLER *************************/
308
309 static struct alias_entry *alias_list = NULL;
310
311 static int AddAliasEntry(const char *original_name, const char *aliased_name, const int is_delete)
312 {
313 struct alias_entry *new_entry, *ptr;
314 static DECLARE_MUTEX(lock);
315 const struct path_info *saved_original_name, *saved_aliased_name;
316 int error = -ENOMEM;
317 if (!IsCorrectPath(original_name, 1, -1, -1, __FUNCTION__) || !IsCorrectPath(aliased_name, 1, -1, -1, __FUNCTION__)) return -EINVAL; /* No patterns allowed. */
318 if ((saved_original_name = SaveName(original_name)) == NULL || (saved_aliased_name = SaveName(aliased_name)) == NULL) return -ENOMEM;
319 down(&lock);
320 for (ptr = alias_list; ptr; ptr = ptr->next) {
321 if (ptr->original_name == saved_original_name && ptr->aliased_name == saved_aliased_name) {
322 ptr->is_deleted = is_delete;
323 error = 0;
324 goto out;
325 }
326 }
327 if (is_delete) {
328 error = -ENOENT;
329 goto out;
330 }
331 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
332 new_entry->original_name = saved_original_name;
333 new_entry->aliased_name = saved_aliased_name;
334 mb(); /* Avoid out-of-order execution. */
335 if ((ptr = alias_list) != NULL) {
336 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;
337 } else {
338 alias_list = new_entry;
339 }
340 error = 0;
341 out:
342 up(&lock);
343 return error;
344 }
345
346 int ReadAliasPolicy(struct io_buffer *head)
347 {
348 struct alias_entry *ptr = head->read_var2;
349 if (!ptr) ptr = alias_list;
350 while (ptr) {
351 head->read_var2 = ptr;
352 if (!ptr->is_deleted && io_printf(head, KEYWORD_ALIAS "%s %s\n", ptr->original_name->name, ptr->aliased_name->name)) break;
353 ptr = ptr->next;
354 }
355 return ptr ? -ENOMEM : 0;
356 }
357
358 int AddAliasPolicy(char *data, const int is_delete)
359 {
360 char *cp = strchr(data, ' ');
361 if (!cp) return -EINVAL;
362 *cp++ = '\0';
363 return AddAliasEntry(data, cp, is_delete);
364 }
365
366 /************************* DOMAIN AGGREGATOR HANDLER *************************/
367
368 static struct aggregator_entry *aggregator_list = NULL;
369
370 static int AddAggregatorEntry(const char *original_name, const char *aggregated_name, const int is_delete)
371 {
372 struct aggregator_entry *new_entry, *ptr;
373 static DECLARE_MUTEX(lock);
374 const struct path_info *saved_original_name, *saved_aggregated_name;
375 int error = -ENOMEM;
376 if (!IsCorrectPath(original_name, 1, 0, -1, __FUNCTION__) || !IsCorrectPath(aggregated_name, 1, -1, -1, __FUNCTION__)) return -EINVAL;
377 if ((saved_original_name = SaveName(original_name)) == NULL || (saved_aggregated_name = SaveName(aggregated_name)) == NULL) return -ENOMEM;
378 down(&lock);
379 for (ptr = aggregator_list; ptr; ptr = ptr->next) {
380 if (ptr->original_name == saved_original_name && ptr->aggregated_name == saved_aggregated_name) {
381 ptr->is_deleted = is_delete;
382 error = 0;
383 goto out;
384 }
385 }
386 if (is_delete) {
387 error = -ENOENT;
388 goto out;
389 }
390 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
391 new_entry->original_name = saved_original_name;
392 new_entry->aggregated_name = saved_aggregated_name;
393 mb(); /* Avoid out-of-order execution. */
394 if ((ptr = aggregator_list) != NULL) {
395 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;
396 } else {
397 aggregator_list = new_entry;
398 }
399 error = 0;
400 out:
401 up(&lock);
402 return error;
403 }
404
405 int ReadAggregatorPolicy(struct io_buffer *head)
406 {
407 struct aggregator_entry *ptr = head->read_var2;
408 if (!ptr) ptr = aggregator_list;
409 while (ptr) {
410 head->read_var2 = ptr;
411 if (!ptr->is_deleted && io_printf(head, KEYWORD_AGGREGATOR "%s %s\n", ptr->original_name->name, ptr->aggregated_name->name)) break;
412 ptr = ptr->next;
413 }
414 return ptr ? -ENOMEM : 0;
415 }
416
417 int AddAggregatorPolicy(char *data, const int is_delete)
418 {
419 char *cp = strchr(data, ' ');
420 if (!cp) return -EINVAL;
421 *cp++ = '\0';
422 return AddAggregatorEntry(data, cp, is_delete);
423 }
424
425 /************************* DOMAIN DELETION HANDLER *************************/
426
427 /* #define DEBUG_DOMAIN_UNDELETE */
428
429 int DeleteDomain(char *domainname0)
430 {
431 struct domain_info *domain;
432 struct path_info domainname;
433 domainname.name = domainname0;
434 fill_path_info(&domainname);
435 down(&new_domain_assign_lock);
436 #ifdef DEBUG_DOMAIN_UNDELETE
437 printk("DeleteDomain %s\n", domainname0);
438 for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {
439 if (pathcmp(domain->domainname, &domainname)) continue;
440 printk("List: %p %u\n", domain, domain->is_deleted);
441 }
442 #endif
443 /* Is there an active domain? */
444 for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) { /* Never delete KERNEL_DOMAIN */
445 if (domain->is_deleted || pathcmp(domain->domainname, &domainname)) continue;
446 break;
447 }
448 if (domain) {
449 struct domain_info *domain2;
450 /* Mark already deleted domains as non undeletable. */
451 for (domain2 = KERNEL_DOMAIN.next; domain2; domain2 = domain2->next) {
452 if (!domain2->is_deleted || pathcmp(domain2->domainname, &domainname)) continue;
453 #ifdef DEBUG_DOMAIN_UNDELETE
454 if (domain2->is_deleted != 255) printk("Marked %p as non undeletable\n", domain2);
455 #endif
456 domain2->is_deleted = 255;
457 }
458 /* Delete and mark active domain as undeletable. */
459 domain->is_deleted = 1;
460 #ifdef DEBUG_DOMAIN_UNDELETE
461 printk("Marked %p as undeletable\n", domain);
462 #endif
463 }
464 up(&new_domain_assign_lock);
465 return 0;
466 }
467
468 struct domain_info *UndeleteDomain(const char *domainname0)
469 {
470 struct domain_info *domain, *candidate_domain = NULL;
471 struct path_info domainname;
472 domainname.name = domainname0;
473 fill_path_info(&domainname);
474 down(&new_domain_assign_lock);
475 #ifdef DEBUG_DOMAIN_UNDELETE
476 printk("UndeleteDomain %s\n", domainname0);
477 for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {
478 if (pathcmp(domain->domainname, &domainname)) continue;
479 printk("List: %p %u\n", domain, domain->is_deleted);
480 }
481 #endif
482 for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {
483 if (pathcmp(&domainname, domain->domainname)) continue;
484 if (!domain->is_deleted) {
485 /* This domain is active. I can't undelete. */
486 candidate_domain = NULL;
487 #ifdef DEBUG_DOMAIN_UNDELETE
488 printk("%p is active. I can't undelete.\n", domain);
489 #endif
490 break;
491 }
492 /* Is this domain undeletable? */
493 if (domain->is_deleted == 1) candidate_domain = domain;
494 }
495 if (candidate_domain) {
496 candidate_domain->is_deleted = 0;
497 #ifdef DEBUG_DOMAIN_UNDELETE
498 printk("%p was undeleted.\n", candidate_domain);
499 #endif
500 }
501 up(&new_domain_assign_lock);
502 return candidate_domain;
503 }
504
505 /************************* DOMAIN TRANSITION HANDLER *************************/
506
507 struct domain_info *FindOrAssignNewDomain(const char *domainname, const u8 profile)
508 {
509 struct domain_info *domain = NULL;
510 const struct path_info *saved_domainname;
511 down(&new_domain_assign_lock);
512 if ((domain = FindDomain(domainname)) != NULL) goto out;
513 if (!IsCorrectDomain(domainname, __FUNCTION__)) goto out;
514 if ((saved_domainname = SaveName(domainname)) == NULL) goto out;
515 /* Can I reuse memory of deleted domain? */
516 for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {
517 struct task_struct *p;
518 struct acl_info *ptr;
519 int flag;
520 if (!domain->is_deleted || domain->domainname != saved_domainname) continue;
521 flag = 0;
522 /***** CRITICAL SECTION START *****/
523 read_lock(&tasklist_lock);
524 for_each_process(p) {
525 if (p->domain_info == domain) { flag = 1; break; }
526 }
527 read_unlock(&tasklist_lock);
528 /***** CRITICAL SECTION END *****/
529 if (flag) continue;
530 #ifdef DEBUG_DOMAIN_UNDELETE
531 printk("Reusing %p %s\n", domain, domain->domainname->name);
532 #endif
533 for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) ptr->is_deleted = 1;
534 domain->profile = profile;
535 domain->quota_warned = 0;
536 mb(); /* Avoid out-of-order execution. */
537 domain->is_deleted = 0;
538 goto out;
539 }
540 /* No memory reusable. Create using new memory. */
541 if ((domain = alloc_element(sizeof(*domain))) != NULL) {
542 struct domain_info *ptr = &KERNEL_DOMAIN;
543 domain->domainname = saved_domainname;
544 domain->profile = profile;
545 mb(); /* Avoid out-of-order execution. */
546 while (ptr->next) ptr = ptr->next; ptr->next = domain;
547 }
548 out: ;
549 up(&new_domain_assign_lock);
550 return domain;
551 }
552
553 static int Escape(char *dest, const char *src, int dest_len)
554 {
555 while (*src) {
556 const unsigned char c = * (const unsigned char *) src;
557 if (c == '\\') {
558 dest_len -= 2;
559 if (dest_len <= 0) goto out;
560 *dest++ = '\\';
561 *dest++ = '\\';
562 } else if (c > ' ' && c < 127) {
563 if (--dest_len <= 0) goto out;
564 *dest++ = c;
565 } else {
566 dest_len -= 4;
567 if (dest_len <= 0) goto out;
568 *dest++ = '\\';
569 *dest++ = (c >> 6) + '0';
570 *dest++ = ((c >> 3) & 7) + '0';
571 *dest++ = (c & 7) + '0';
572 }
573 src++;
574 }
575 if (--dest_len <= 0) goto out;
576 *dest = '\0';
577 return 0;
578 out:
579 return -ENOMEM;
580 }
581
582 static char *get_argv0(struct linux_binprm *bprm)
583 {
584 char *arg_ptr = ccs_alloc(PAGE_SIZE); /* Initial buffer. */
585 int arg_len = 0;
586 unsigned long pos = bprm->p;
587 int i = pos / PAGE_SIZE, offset = pos % PAGE_SIZE;
588 if (!bprm->argc || !arg_ptr) goto out;
589 while (1) {
590 struct page *page;
591 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)
592 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0) goto out;
593 #else
594 page = bprm->page[i];
595 #endif
596 { /* Map and copy to kernel buffer and unmap. */
597 const char *kaddr = kmap(page);
598 if (!kaddr) { /* Mapping failed. */
599 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)
600 put_page(page);
601 #endif
602 goto out;
603 }
604 memmove(arg_ptr + arg_len, kaddr + offset, PAGE_SIZE - offset);
605 kunmap(page);
606 }
607 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)
608 put_page(page);
609 pos += PAGE_SIZE - offset;
610 #endif
611 arg_len += PAGE_SIZE - offset;
612 if (memchr(arg_ptr, '\0', arg_len)) break;
613 { /* Initial buffer was too small for argv[0]. Retry after expanding buffer. */
614 char *tmp_arg_ptr = ccs_alloc(arg_len + PAGE_SIZE);
615 if (!tmp_arg_ptr) goto out;
616 memmove(tmp_arg_ptr, arg_ptr, arg_len);
617 ccs_free(arg_ptr);
618 arg_ptr = tmp_arg_ptr;
619 }
620 i++;
621 offset = 0;
622 }
623 return arg_ptr;
624 out: /* Release initial buffer. */
625 ccs_free(arg_ptr);
626 return NULL;
627 }
628
629 static int FindNextDomain(struct linux_binprm *bprm, struct domain_info **next_domain)
630 {
631 /* This function assumes that the size of buffer returned by realpath() = CCS_MAX_PATHNAME_LEN. */
632 struct domain_info *old_domain = current->domain_info, *domain = NULL;
633 const char *old_domain_name = old_domain->domainname->name;
634 const char *original_name = bprm->filename;
635 struct file *filp = bprm->file;
636 char *new_domain_name = NULL;
637 char *real_program_name = NULL, *symlink_program_name = NULL;
638 const int is_enforce = CheckCCSEnforce(CCS_TOMOYO_MAC_FOR_FILE);
639 int retval;
640 struct path_info r, s, l;
641
642 {
643 /*
644 * Built-in initializers. This is needed because policies are not loaded until starting /sbin/init .
645 */
646 static int first = 1;
647 if (first) {
648 AddDomainInitializerEntry(NULL, "/sbin/hotplug", 0, 0);
649 AddDomainInitializerEntry(NULL, "/sbin/modprobe", 0, 0);
650 first = 0;
651 }
652 }
653
654 /* Get realpath of program. */
655 retval = -ENOENT; /* I hope realpath() won't fail with -ENOMEM. */
656 if ((real_program_name = realpath(original_name)) == NULL) goto out;
657 /* Get realpath of symbolic link. */
658 if ((symlink_program_name = realpath_nofollow(original_name)) == NULL) goto out;
659
660 r.name = real_program_name;
661 fill_path_info(&r);
662 s.name = symlink_program_name;
663 fill_path_info(&s);
664 if ((l.name = strrchr(old_domain_name, ' ')) != NULL) l.name++;
665 else l.name = old_domain_name;
666 fill_path_info(&l);
667
668 /* Check 'alias' directive. */
669 if (pathcmp(&r, &s)) {
670 struct alias_entry *ptr;
671 /* Is this program allowed to be called via symbolic links? */
672 for (ptr = alias_list; ptr; ptr = ptr->next) {
673 if (ptr->is_deleted || pathcmp(&r, ptr->original_name) || pathcmp(&s, ptr->aliased_name)) continue;
674 memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);
675 strncpy(real_program_name, ptr->aliased_name->name, CCS_MAX_PATHNAME_LEN - 1);
676 fill_path_info(&r);
677 break;
678 }
679 }
680
681 /* Compare basename of real_program_name and argv[0] */
682 if (bprm->argc > 0 && CheckCCSFlags(CCS_TOMOYO_MAC_FOR_ARGV0)) {
683 char *org_argv0 = get_argv0(bprm);
684 retval = -ENOMEM;
685 if (org_argv0) {
686 const int len = strlen(org_argv0);
687 char *printable_argv0 = ccs_alloc(len * 4 + 8);
688 if (printable_argv0 && Escape(printable_argv0, org_argv0, len * 4 + 8) == 0) {
689 const char *base_argv0, *base_filename;
690 if ((base_argv0 = strrchr(printable_argv0, '/')) == NULL) base_argv0 = printable_argv0; else base_argv0++;
691 if ((base_filename = strrchr(real_program_name, '/')) == NULL) base_filename = real_program_name; else base_filename++;
692 if (strcmp(base_argv0, base_filename)) retval = CheckArgv0Perm(&r, base_argv0);
693 else retval = 0;
694 }
695 ccs_free(printable_argv0);
696 ccs_free(org_argv0);
697 }
698 if (retval) goto out;
699 }
700
701 /* Check 'aggregator' directive. */
702 {
703 struct aggregator_entry *ptr;
704 /* Is this program allowed to be aggregated? */
705 for (ptr = aggregator_list; ptr; ptr = ptr->next) {
706 if (ptr->is_deleted || !PathMatchesToPattern(&r, ptr->original_name)) continue;
707 memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);
708 strncpy(real_program_name, ptr->aggregated_name->name, CCS_MAX_PATHNAME_LEN - 1);
709 fill_path_info(&r);
710 break;
711 }
712 }
713
714 /* Check execute permission. */
715 if ((retval = CheckExecPerm(&r, filp)) < 0) goto out;
716
717 /* Allocate memory for calcurating domain name. */
718 retval = -ENOMEM;
719 if ((new_domain_name = ccs_alloc(CCS_MAX_PATHNAME_LEN + 16)) == NULL) goto out;
720
721 if (IsDomainInitializer(old_domain->domainname, &r, &l)) {
722 /* Transit to the child of KERNEL_DOMAIN domain. */
723 snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1, ROOT_NAME " " "%s", real_program_name);
724 } else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) {
725 /*
726 * Needn't to transit from kernel domain before starting /sbin/init .
727 * But transit from kernel domain if executing initializers, for they might start before /sbin/init .
728 */
729 domain = old_domain;
730 } else if (IsDomainKeeper(old_domain->domainname, &r, &l)) {
731 /* Keep current domain. */
732 domain = old_domain;
733 } else {
734 /* Normal domain transition. */
735 snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1, "%s %s", old_domain_name, real_program_name);
736 }
737 if (!domain && strlen(new_domain_name) < CCS_MAX_PATHNAME_LEN) {
738 if (is_enforce) {
739 domain = FindDomain(new_domain_name);
740 if (!domain) if (CheckSupervisor("#Need to create domain\n%s\n", new_domain_name) == 0) domain = FindOrAssignNewDomain(new_domain_name, current->domain_info->profile);
741 } else {
742 domain = FindOrAssignNewDomain(new_domain_name, current->domain_info->profile);
743 }
744 }
745 if (!domain) {
746 printk("TOMOYO-ERROR: Domain '%s' not defined.\n", new_domain_name);
747 if (is_enforce) retval = -EPERM;
748 } else {
749 retval = 0;
750 }
751 out: ;
752 ccs_free(new_domain_name);
753 ccs_free(real_program_name);
754 ccs_free(symlink_program_name);
755 *next_domain = domain ? domain : old_domain;
756 return retval;
757 }
758
759 #endif
760
761 int search_binary_handler_with_transition(struct linux_binprm *bprm, struct pt_regs *regs)
762 {
763 struct domain_info *next_domain = NULL, *prev_domain = current->domain_info;
764 int retval;
765 #if defined(CONFIG_SAKURA) || defined(CONFIG_TOMOYO)
766 extern void CCS_LoadPolicy(const char *filename);
767 CCS_LoadPolicy(bprm->filename);
768 #endif
769 #if defined(CONFIG_TOMOYO)
770 retval = FindNextDomain(bprm, &next_domain);
771 #else
772 retval = 0; next_domain = prev_domain;
773 #endif
774 if (retval == 0) {
775 current->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
776 current->domain_info = next_domain;
777 retval = search_binary_handler(bprm, regs);
778 if (retval < 0) current->domain_info = prev_domain;
779 current->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
780 }
781 return retval;
782 }
783
784 /***** TOMOYO Linux end. *****/

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