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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 502 - (show annotations) (download) (as text)
Tue Sep 25 13:33:45 2007 UTC (16 years, 8 months ago) by kumaneko
Original Path: trunk/1.5.x/ccs-patch/fs/tomoyo_domain.c
File MIME type: text/x-csrc
File size: 25158 byte(s)


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

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