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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 141 - (hide 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 kumaneko 111 /*
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 kumaneko 141 * Version: 1.3.3 2007/04/01
9 kumaneko 111 *
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 kumaneko 115 #include <linux/highmem.h>
20     #include <linux/binfmts.h>
21    
22 kumaneko 111 #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 kumaneko 120 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 kumaneko 111 /************************* 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 kumaneko 115 static char *get_argv0(struct linux_binprm *bprm)
633 kumaneko 111 {
634 kumaneko 115 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 kumaneko 111 /* 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 kumaneko 115 const char *original_name = bprm->filename;
671     struct file *filp = bprm->file;
672 kumaneko 111 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 kumaneko 115 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 kumaneko 111 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 kumaneko 115 else retval = 0;
743 kumaneko 111 }
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 kumaneko 115 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 kumaneko 111 /***** TOMOYO Linux end. *****/

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