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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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