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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 473 - (hide annotations) (download) (as text)
Thu Sep 20 12:18:18 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: 25161 byte(s)
1.5.0-rc
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 473 * Version: 1.5.0-rc 2007/09/20
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 kumaneko 214 struct domain_initializer_entry {
44 kumaneko 111 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 kumaneko 214 };
51 kumaneko 111
52     /***** The structure for domains to not to transit domains. *****/
53    
54 kumaneko 214 struct domain_keeper_entry {
55 kumaneko 111 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 kumaneko 214 };
62 kumaneko 111
63     /***** The structure for program files that should be aggregated. *****/
64    
65 kumaneko 214 struct aggregator_entry {
66 kumaneko 111 struct aggregator_entry *next;
67     const struct path_info *original_name;
68     const struct path_info *aggregated_name;
69     int is_deleted;
70 kumaneko 214 };
71 kumaneko 111
72     /***** The structure for program files that should be aliased. *****/
73    
74 kumaneko 214 struct alias_entry {
75 kumaneko 111 struct alias_entry *next;
76     const struct path_info *original_name;
77     const struct path_info *aliased_name;
78     int is_deleted;
79 kumaneko 214 };
80 kumaneko 111
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 kumaneko 120 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 kumaneko 329 /* If there are so many entries, don't append if learning mode. */
118 kumaneko 120 if (count < CheckCCSFlags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) return 0;
119     if (!domain->quota_warned) {
120 kumaneko 329 printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. Stopped learning mode.\n", domain->domainname->name);
121 kumaneko 120 domain->quota_warned = 1;
122     }
123     return 1;
124     }
125    
126    
127 kumaneko 111 /************************* DOMAIN INITIALIZER HANDLER *************************/
128    
129 kumaneko 214 static struct domain_initializer_entry *domain_initializer_list = NULL;
130 kumaneko 111
131 kumaneko 366 static int AddDomainInitializerEntry(const char *domainname, const char *program, const int is_not, const int is_delete)
132 kumaneko 111 {
133 kumaneko 214 struct domain_initializer_entry *new_entry, *ptr;
134 kumaneko 111 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 kumaneko 366 if (ptr->is_not == is_not && ptr->domainname == saved_domainname && ptr->program == saved_program) {
151 kumaneko 111 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 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
161 kumaneko 111 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 kumaneko 214 int ReadDomainInitializerPolicy(struct io_buffer *head)
178 kumaneko 111 {
179 kumaneko 214 struct domain_initializer_entry *ptr = head->read_var2;
180 kumaneko 111 if (!ptr) ptr = domain_initializer_list;
181     while (ptr) {
182 kumaneko 214 head->read_var2 = ptr;
183 kumaneko 111 if (!ptr->is_deleted) {
184     if (ptr->domainname) {
185 kumaneko 366 if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s from %s\n", ptr->is_not ? "no_" : "", ptr->program->name, ptr->domainname->name)) break;
186 kumaneko 111 } else {
187 kumaneko 366 if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s\n", ptr->is_not ? "no_" : "", ptr->program->name)) break;
188 kumaneko 111 }
189     }
190     ptr = ptr->next;
191     }
192     return ptr ? -ENOMEM : 0;
193     }
194    
195 kumaneko 366 int AddDomainInitializerPolicy(char *data, const int is_not, const int is_delete)
196 kumaneko 111 {
197     char *cp = strstr(data, " from ");
198     if (cp) {
199     *cp = '\0';
200 kumaneko 366 return AddDomainInitializerEntry(cp + 6, data, is_not, is_delete);
201 kumaneko 111 } else {
202 kumaneko 366 return AddDomainInitializerEntry(NULL, data, is_not, is_delete);
203 kumaneko 111 }
204     }
205    
206     static int IsDomainInitializer(const struct path_info *domainname, const struct path_info *program, const struct path_info *last_name)
207     {
208 kumaneko 214 struct domain_initializer_entry *ptr;
209 kumaneko 111 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 kumaneko 214 static struct domain_keeper_entry *domain_keeper_list = NULL;
229 kumaneko 111
230     static int AddDomainKeeperEntry(const char *domainname, const char *program, const int is_not, const int is_delete)
231     {
232 kumaneko 214 struct domain_keeper_entry *new_entry, *ptr;
233 kumaneko 111 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 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
260 kumaneko 111 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 kumaneko 214 int ReadDomainKeeperPolicy(struct io_buffer *head)
288 kumaneko 111 {
289 kumaneko 214 struct domain_keeper_entry *ptr = head->read_var2;
290 kumaneko 111 if (!ptr) ptr = domain_keeper_list;
291     while (ptr) {
292 kumaneko 214 head->read_var2 = ptr;
293 kumaneko 111 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 kumaneko 214 struct domain_keeper_entry *ptr;
308 kumaneko 111 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 kumaneko 214 static struct alias_entry *alias_list = NULL;
326 kumaneko 111
327     static int AddAliasEntry(const char *original_name, const char *aliased_name, const int is_delete)
328     {
329 kumaneko 214 struct alias_entry *new_entry, *ptr;
330 kumaneko 111 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 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
348 kumaneko 111 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 kumaneko 214 int ReadAliasPolicy(struct io_buffer *head)
363 kumaneko 111 {
364 kumaneko 214 struct alias_entry *ptr = head->read_var2;
365 kumaneko 111 if (!ptr) ptr = alias_list;
366     while (ptr) {
367 kumaneko 214 head->read_var2 = ptr;
368 kumaneko 111 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 kumaneko 214 static struct aggregator_entry *aggregator_list = NULL;
385 kumaneko 111
386     static int AddAggregatorEntry(const char *original_name, const char *aggregated_name, const int is_delete)
387     {
388 kumaneko 214 struct aggregator_entry *new_entry, *ptr;
389 kumaneko 111 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 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
407 kumaneko 111 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 kumaneko 214 int ReadAggregatorPolicy(struct io_buffer *head)
422 kumaneko 111 {
423 kumaneko 214 struct aggregator_entry *ptr = head->read_var2;
424 kumaneko 111 if (!ptr) ptr = aggregator_list;
425     while (ptr) {
426 kumaneko 214 head->read_var2 = ptr;
427 kumaneko 111 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 kumaneko 240 /* #define DEBUG_DOMAIN_UNDELETE */
444 kumaneko 111
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 kumaneko 214 if ((domain = alloc_element(sizeof(*domain))) != NULL) {
558 kumaneko 111 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 kumaneko 115 static char *get_argv0(struct linux_binprm *bprm)
599 kumaneko 111 {
600 kumaneko 316 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 kumaneko 115 const char *kaddr = kmap(page);
614 kumaneko 316 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 kumaneko 115 memmove(arg_ptr + arg_len, kaddr + offset, PAGE_SIZE - offset);
621     kunmap(page);
622     }
623 kumaneko 316 #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 kumaneko 115 }
639 kumaneko 316 return arg_ptr;
640     out: /* Release initial buffer. */
641     ccs_free(arg_ptr);
642 kumaneko 115 return NULL;
643     }
644    
645     static int FindNextDomain(struct linux_binprm *bprm, struct domain_info **next_domain)
646     {
647 kumaneko 111 /* 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 kumaneko 115 const char *original_name = bprm->filename;
651     struct file *filp = bprm->file;
652 kumaneko 111 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 kumaneko 366 AddDomainInitializerEntry(NULL, "/sbin/hotplug", 0, 0);
665     AddDomainInitializerEntry(NULL, "/sbin/modprobe", 0, 0);
666 kumaneko 111 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 kumaneko 214 struct alias_entry *ptr;
687 kumaneko 111 /* 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 kumaneko 183 /* Compare basename of real_program_name and argv[0] */
698 kumaneko 115 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 kumaneko 111 const char *base_argv0, *base_filename;
706     if ((base_argv0 = strrchr(printable_argv0, '/')) == NULL) base_argv0 = printable_argv0; else base_argv0++;
707 kumaneko 183 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 kumaneko 115 else retval = 0;
710 kumaneko 111 }
711     ccs_free(printable_argv0);
712     ccs_free(org_argv0);
713     }
714     if (retval) goto out;
715     }
716    
717 kumaneko 183 /* Check 'aggregator' directive. */
718     {
719 kumaneko 214 struct aggregator_entry *ptr;
720 kumaneko 183 /* 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 kumaneko 111 /* 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 kumaneko 115 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 kumaneko 111 /***** TOMOYO Linux end. *****/

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