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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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