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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 986 - (hide annotations) (download) (as text)
Thu Feb 14 04:30:46 2008 UTC (16 years, 3 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/tomoyo_domain.c
File MIME type: text/x-csrc
File size: 28527 byte(s)


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

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