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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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