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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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