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

Subversion リポジトリの参照

Annotation of /branches/ccs-patch/fs/ccsecurity/domain.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 851 - (hide annotations) (download) (as text)
Wed Jan 2 06:29:56 2008 UTC (16 years, 5 months ago) by kumaneko
Original Path: trunk/1.5.x/ccs-patch/fs/tomoyo_domain.c
File MIME type: text/x-csrc
File size: 28451 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 851 * Version: 1.5.3-pre 2008/01/02
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     extern int sbin_init_started;
36    
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 722 list1_add_tail_mb(&acl->list, &domain->acl_info_list);
101 kumaneko 111 UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
102     return 0;
103     }
104    
105     int DelDomainACL(struct acl_info *ptr)
106     {
107     ptr->is_deleted = 1;
108     UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
109     return 0;
110     }
111    
112     /************************* DOMAIN INITIALIZER HANDLER *************************/
113    
114 kumaneko 722 static LIST1_HEAD(domain_initializer_list);
115 kumaneko 111
116 kumaneko 621 static int AddDomainInitializerEntry(const char *domainname, const char *program, const bool is_not, const bool is_delete)
117 kumaneko 111 {
118 kumaneko 214 struct domain_initializer_entry *new_entry, *ptr;
119 kumaneko 652 static DEFINE_MUTEX(lock);
120 kumaneko 111 const struct path_info *saved_program, *saved_domainname = NULL;
121     int error = -ENOMEM;
122 kumaneko 621 bool is_last_name = 0;
123 kumaneko 111 if (!IsCorrectPath(program, 1, -1, -1, __FUNCTION__)) return -EINVAL; /* No patterns allowed. */
124     if (domainname) {
125     if (!IsDomainDef(domainname) && IsCorrectPath(domainname, 1, -1, -1, __FUNCTION__)) {
126     is_last_name = 1;
127     } else if (!IsCorrectDomain(domainname, __FUNCTION__)) {
128     return -EINVAL;
129     }
130     if ((saved_domainname = SaveName(domainname)) == NULL) return -ENOMEM;
131     }
132     if ((saved_program = SaveName(program)) == NULL) return -ENOMEM;
133 kumaneko 652 mutex_lock(&lock);
134 kumaneko 722 list1_for_each_entry(ptr, &domain_initializer_list, list) {
135 kumaneko 366 if (ptr->is_not == is_not && ptr->domainname == saved_domainname && ptr->program == saved_program) {
136 kumaneko 111 ptr->is_deleted = is_delete;
137     error = 0;
138     goto out;
139     }
140     }
141     if (is_delete) {
142     error = -ENOENT;
143     goto out;
144     }
145 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
146 kumaneko 111 new_entry->domainname = saved_domainname;
147     new_entry->program = saved_program;
148     new_entry->is_not = is_not;
149     new_entry->is_last_name = is_last_name;
150 kumaneko 722 list1_add_tail_mb(&new_entry->list, &domain_initializer_list);
151 kumaneko 111 error = 0;
152     out:
153 kumaneko 652 mutex_unlock(&lock);
154 kumaneko 111 return error;
155     }
156    
157 kumaneko 214 int ReadDomainInitializerPolicy(struct io_buffer *head)
158 kumaneko 111 {
159 kumaneko 722 struct list1_head *pos;
160     list1_for_each_cookie(pos, head->read_var2, &domain_initializer_list) {
161 kumaneko 708 struct domain_initializer_entry *ptr;
162 kumaneko 722 ptr = list1_entry(pos, struct domain_initializer_entry, list);
163 kumaneko 708 if (ptr->is_deleted) continue;
164     if (ptr->domainname) {
165     if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s from %s\n", ptr->is_not ? "no_" : "", ptr->program->name, ptr->domainname->name)) return -ENOMEM;
166     } else {
167     if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s\n", ptr->is_not ? "no_" : "", ptr->program->name)) return -ENOMEM;
168 kumaneko 111 }
169     }
170 kumaneko 708 return 0;
171 kumaneko 111 }
172    
173 kumaneko 621 int AddDomainInitializerPolicy(char *data, const bool is_not, const bool is_delete)
174 kumaneko 111 {
175     char *cp = strstr(data, " from ");
176     if (cp) {
177     *cp = '\0';
178 kumaneko 366 return AddDomainInitializerEntry(cp + 6, data, is_not, is_delete);
179 kumaneko 111 } else {
180 kumaneko 366 return AddDomainInitializerEntry(NULL, data, is_not, is_delete);
181 kumaneko 111 }
182     }
183    
184 kumaneko 708 static bool IsDomainInitializer(const struct path_info *domainname, const struct path_info *program, const struct path_info *last_name)
185 kumaneko 111 {
186 kumaneko 214 struct domain_initializer_entry *ptr;
187 kumaneko 708 bool flag = 0;
188 kumaneko 722 list1_for_each_entry(ptr, &domain_initializer_list, list) {
189 kumaneko 708 if (ptr->is_deleted) continue;
190 kumaneko 111 if (ptr->domainname) {
191     if (!ptr->is_last_name) {
192     if (ptr->domainname != domainname) continue;
193     } else {
194     if (pathcmp(ptr->domainname, last_name)) continue;
195     }
196     }
197     if (pathcmp(ptr->program, program)) continue;
198     if (ptr->is_not) return 0;
199     flag = 1;
200     }
201     return flag;
202     }
203    
204     /************************* DOMAIN KEEPER HANDLER *************************/
205    
206 kumaneko 722 static LIST1_HEAD(domain_keeper_list);
207 kumaneko 111
208 kumaneko 621 static int AddDomainKeeperEntry(const char *domainname, const char *program, const bool is_not, const bool is_delete)
209 kumaneko 111 {
210 kumaneko 214 struct domain_keeper_entry *new_entry, *ptr;
211 kumaneko 111 const struct path_info *saved_domainname, *saved_program = NULL;
212 kumaneko 652 static DEFINE_MUTEX(lock);
213 kumaneko 111 int error = -ENOMEM;
214 kumaneko 621 bool is_last_name = 0;
215 kumaneko 111 if (!IsDomainDef(domainname) && IsCorrectPath(domainname, 1, -1, -1, __FUNCTION__)) {
216     is_last_name = 1;
217     } else if (!IsCorrectDomain(domainname, __FUNCTION__)) {
218     return -EINVAL;
219     }
220     if (program) {
221     if (!IsCorrectPath(program, 1, -1, -1, __FUNCTION__)) return -EINVAL;
222     if ((saved_program = SaveName(program)) == NULL) return -ENOMEM;
223     }
224     if ((saved_domainname = SaveName(domainname)) == NULL) return -ENOMEM;
225 kumaneko 652 mutex_lock(&lock);
226 kumaneko 722 list1_for_each_entry(ptr, &domain_keeper_list, list) {
227 kumaneko 111 if (ptr->is_not == is_not && ptr->domainname == saved_domainname && ptr->program == saved_program) {
228     ptr->is_deleted = is_delete;
229     error = 0;
230     goto out;
231     }
232     }
233     if (is_delete) {
234     error = -ENOENT;
235     goto out;
236     }
237 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
238 kumaneko 111 new_entry->domainname = saved_domainname;
239     new_entry->program = saved_program;
240     new_entry->is_not = is_not;
241     new_entry->is_last_name = is_last_name;
242 kumaneko 722 list1_add_tail_mb(&new_entry->list, &domain_keeper_list);
243 kumaneko 111 error = 0;
244     out:
245 kumaneko 652 mutex_unlock(&lock);
246 kumaneko 111 return error;
247     }
248    
249 kumaneko 621 int AddDomainKeeperPolicy(char *data, const bool is_not, const bool is_delete)
250 kumaneko 111 {
251     char *cp = strstr(data, " from ");
252     if (cp) {
253     *cp = '\0';
254     return AddDomainKeeperEntry(cp + 6, data, is_not, is_delete);
255     } else {
256     return AddDomainKeeperEntry(data, NULL, is_not, is_delete);
257     }
258     }
259    
260 kumaneko 214 int ReadDomainKeeperPolicy(struct io_buffer *head)
261 kumaneko 111 {
262 kumaneko 722 struct list1_head *pos;
263     list1_for_each_cookie(pos, head->read_var2, &domain_keeper_list) {
264 kumaneko 708 struct domain_keeper_entry *ptr;
265 kumaneko 722 ptr = list1_entry(pos, struct domain_keeper_entry, list);
266 kumaneko 708 if (ptr->is_deleted) continue;
267     if (ptr->program) {
268     if (io_printf(head, "%s" KEYWORD_KEEP_DOMAIN "%s from %s\n", ptr->is_not ? "no_" : "", ptr->program->name, ptr->domainname->name)) return -ENOMEM;
269     } else {
270     if (io_printf(head, "%s" KEYWORD_KEEP_DOMAIN "%s\n", ptr->is_not ? "no_" : "", ptr->domainname->name)) return -ENOMEM;
271 kumaneko 111 }
272     }
273 kumaneko 708 return 0;
274 kumaneko 111 }
275    
276 kumaneko 708 static bool IsDomainKeeper(const struct path_info *domainname, const struct path_info *program, const struct path_info *last_name)
277 kumaneko 111 {
278 kumaneko 214 struct domain_keeper_entry *ptr;
279 kumaneko 708 bool flag = 0;
280 kumaneko 722 list1_for_each_entry(ptr, &domain_keeper_list, list) {
281 kumaneko 111 if (ptr->is_deleted) continue;
282     if (!ptr->is_last_name) {
283     if (ptr->domainname != domainname) continue;
284     } else {
285 kumaneko 708 if (pathcmp(ptr->domainname, last_name)) continue;
286 kumaneko 111 }
287     if (ptr->program && pathcmp(ptr->program, program)) continue;
288     if (ptr->is_not) return 0;
289     flag = 1;
290     }
291     return flag;
292     }
293    
294     /************************* SYMBOLIC LINKED PROGRAM HANDLER *************************/
295    
296 kumaneko 722 static LIST1_HEAD(alias_list);
297 kumaneko 111
298 kumaneko 621 static int AddAliasEntry(const char *original_name, const char *aliased_name, const bool is_delete)
299 kumaneko 111 {
300 kumaneko 214 struct alias_entry *new_entry, *ptr;
301 kumaneko 652 static DEFINE_MUTEX(lock);
302 kumaneko 111 const struct path_info *saved_original_name, *saved_aliased_name;
303     int error = -ENOMEM;
304     if (!IsCorrectPath(original_name, 1, -1, -1, __FUNCTION__) || !IsCorrectPath(aliased_name, 1, -1, -1, __FUNCTION__)) return -EINVAL; /* No patterns allowed. */
305     if ((saved_original_name = SaveName(original_name)) == NULL || (saved_aliased_name = SaveName(aliased_name)) == NULL) return -ENOMEM;
306 kumaneko 652 mutex_lock(&lock);
307 kumaneko 722 list1_for_each_entry(ptr, &alias_list, list) {
308 kumaneko 111 if (ptr->original_name == saved_original_name && ptr->aliased_name == saved_aliased_name) {
309     ptr->is_deleted = is_delete;
310     error = 0;
311     goto out;
312     }
313     }
314     if (is_delete) {
315     error = -ENOENT;
316     goto out;
317     }
318 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
319 kumaneko 111 new_entry->original_name = saved_original_name;
320     new_entry->aliased_name = saved_aliased_name;
321 kumaneko 722 list1_add_tail_mb(&new_entry->list, &alias_list);
322 kumaneko 111 error = 0;
323     out:
324 kumaneko 652 mutex_unlock(&lock);
325 kumaneko 111 return error;
326     }
327    
328 kumaneko 214 int ReadAliasPolicy(struct io_buffer *head)
329 kumaneko 111 {
330 kumaneko 722 struct list1_head *pos;
331     list1_for_each_cookie(pos, head->read_var2, &alias_list) {
332 kumaneko 708 struct alias_entry *ptr;
333 kumaneko 722 ptr = list1_entry(pos, struct alias_entry, list);
334 kumaneko 708 if (ptr->is_deleted) continue;
335     if (io_printf(head, KEYWORD_ALIAS "%s %s\n", ptr->original_name->name, ptr->aliased_name->name)) return -ENOMEM;
336 kumaneko 111 }
337 kumaneko 708 return 0;
338 kumaneko 111 }
339    
340 kumaneko 621 int AddAliasPolicy(char *data, const bool is_delete)
341 kumaneko 111 {
342     char *cp = strchr(data, ' ');
343     if (!cp) return -EINVAL;
344     *cp++ = '\0';
345     return AddAliasEntry(data, cp, is_delete);
346     }
347    
348     /************************* DOMAIN AGGREGATOR HANDLER *************************/
349    
350 kumaneko 722 static LIST1_HEAD(aggregator_list);
351 kumaneko 111
352 kumaneko 621 static int AddAggregatorEntry(const char *original_name, const char *aggregated_name, const bool is_delete)
353 kumaneko 111 {
354 kumaneko 214 struct aggregator_entry *new_entry, *ptr;
355 kumaneko 652 static DEFINE_MUTEX(lock);
356 kumaneko 111 const struct path_info *saved_original_name, *saved_aggregated_name;
357     int error = -ENOMEM;
358     if (!IsCorrectPath(original_name, 1, 0, -1, __FUNCTION__) || !IsCorrectPath(aggregated_name, 1, -1, -1, __FUNCTION__)) return -EINVAL;
359     if ((saved_original_name = SaveName(original_name)) == NULL || (saved_aggregated_name = SaveName(aggregated_name)) == NULL) return -ENOMEM;
360 kumaneko 652 mutex_lock(&lock);
361 kumaneko 722 list1_for_each_entry(ptr, &aggregator_list, list) {
362 kumaneko 111 if (ptr->original_name == saved_original_name && ptr->aggregated_name == saved_aggregated_name) {
363     ptr->is_deleted = is_delete;
364     error = 0;
365     goto out;
366     }
367     }
368     if (is_delete) {
369     error = -ENOENT;
370     goto out;
371     }
372 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
373 kumaneko 111 new_entry->original_name = saved_original_name;
374     new_entry->aggregated_name = saved_aggregated_name;
375 kumaneko 722 list1_add_tail_mb(&new_entry->list, &aggregator_list);
376 kumaneko 111 error = 0;
377     out:
378 kumaneko 652 mutex_unlock(&lock);
379 kumaneko 111 return error;
380     }
381    
382 kumaneko 214 int ReadAggregatorPolicy(struct io_buffer *head)
383 kumaneko 111 {
384 kumaneko 722 struct list1_head *pos;
385     list1_for_each_cookie(pos, head->read_var2, &aggregator_list) {
386 kumaneko 708 struct aggregator_entry *ptr;
387 kumaneko 722 ptr = list1_entry(pos, struct aggregator_entry, list);
388 kumaneko 708 if (ptr->is_deleted) continue;
389     if (io_printf(head, KEYWORD_AGGREGATOR "%s %s\n", ptr->original_name->name, ptr->aggregated_name->name)) return -ENOMEM;
390 kumaneko 111 }
391 kumaneko 708 return 0;
392 kumaneko 111 }
393    
394 kumaneko 621 int AddAggregatorPolicy(char *data, const bool is_delete)
395 kumaneko 111 {
396     char *cp = strchr(data, ' ');
397     if (!cp) return -EINVAL;
398     *cp++ = '\0';
399     return AddAggregatorEntry(data, cp, is_delete);
400     }
401    
402     /************************* DOMAIN DELETION HANDLER *************************/
403    
404 kumaneko 240 /* #define DEBUG_DOMAIN_UNDELETE */
405 kumaneko 111
406     int DeleteDomain(char *domainname0)
407     {
408     struct domain_info *domain;
409     struct path_info domainname;
410     domainname.name = domainname0;
411     fill_path_info(&domainname);
412 kumaneko 652 mutex_lock(&new_domain_assign_lock);
413 kumaneko 111 #ifdef DEBUG_DOMAIN_UNDELETE
414     printk("DeleteDomain %s\n", domainname0);
415 kumaneko 722 list1_for_each_entry(domain, &domain_list, list) {
416 kumaneko 111 if (pathcmp(domain->domainname, &domainname)) continue;
417     printk("List: %p %u\n", domain, domain->is_deleted);
418     }
419     #endif
420     /* Is there an active domain? */
421 kumaneko 722 list1_for_each_entry(domain, &domain_list, list) {
422 kumaneko 111 struct domain_info *domain2;
423 kumaneko 708 /* Never delete KERNEL_DOMAIN */
424     if (domain == &KERNEL_DOMAIN || domain->is_deleted || pathcmp(domain->domainname, &domainname)) continue;
425 kumaneko 111 /* Mark already deleted domains as non undeletable. */
426 kumaneko 722 list1_for_each_entry(domain2, &domain_list, list) {
427 kumaneko 111 if (!domain2->is_deleted || pathcmp(domain2->domainname, &domainname)) continue;
428     #ifdef DEBUG_DOMAIN_UNDELETE
429     if (domain2->is_deleted != 255) printk("Marked %p as non undeletable\n", domain2);
430     #endif
431     domain2->is_deleted = 255;
432     }
433     /* Delete and mark active domain as undeletable. */
434     domain->is_deleted = 1;
435     #ifdef DEBUG_DOMAIN_UNDELETE
436     printk("Marked %p as undeletable\n", domain);
437     #endif
438 kumaneko 708 break;
439 kumaneko 111 }
440 kumaneko 652 mutex_unlock(&new_domain_assign_lock);
441 kumaneko 111 return 0;
442     }
443    
444     struct domain_info *UndeleteDomain(const char *domainname0)
445     {
446     struct domain_info *domain, *candidate_domain = NULL;
447     struct path_info domainname;
448     domainname.name = domainname0;
449     fill_path_info(&domainname);
450 kumaneko 652 mutex_lock(&new_domain_assign_lock);
451 kumaneko 111 #ifdef DEBUG_DOMAIN_UNDELETE
452     printk("UndeleteDomain %s\n", domainname0);
453 kumaneko 722 list1_for_each_entry(domain, &domain_list, list) {
454 kumaneko 111 if (pathcmp(domain->domainname, &domainname)) continue;
455     printk("List: %p %u\n", domain, domain->is_deleted);
456     }
457     #endif
458 kumaneko 722 list1_for_each_entry(domain, &domain_list, list) {
459 kumaneko 111 if (pathcmp(&domainname, domain->domainname)) continue;
460     if (!domain->is_deleted) {
461     /* This domain is active. I can't undelete. */
462     candidate_domain = NULL;
463     #ifdef DEBUG_DOMAIN_UNDELETE
464     printk("%p is active. I can't undelete.\n", domain);
465     #endif
466     break;
467     }
468     /* Is this domain undeletable? */
469     if (domain->is_deleted == 1) candidate_domain = domain;
470     }
471     if (candidate_domain) {
472     candidate_domain->is_deleted = 0;
473     #ifdef DEBUG_DOMAIN_UNDELETE
474     printk("%p was undeleted.\n", candidate_domain);
475     #endif
476     }
477 kumaneko 652 mutex_unlock(&new_domain_assign_lock);
478 kumaneko 111 return candidate_domain;
479     }
480    
481     /************************* DOMAIN TRANSITION HANDLER *************************/
482    
483     struct domain_info *FindOrAssignNewDomain(const char *domainname, const u8 profile)
484     {
485     struct domain_info *domain = NULL;
486     const struct path_info *saved_domainname;
487 kumaneko 652 mutex_lock(&new_domain_assign_lock);
488 kumaneko 111 if ((domain = FindDomain(domainname)) != NULL) goto out;
489     if (!IsCorrectDomain(domainname, __FUNCTION__)) goto out;
490     if ((saved_domainname = SaveName(domainname)) == NULL) goto out;
491     /* Can I reuse memory of deleted domain? */
492 kumaneko 722 list1_for_each_entry(domain, &domain_list, list) {
493 kumaneko 111 struct task_struct *p;
494     struct acl_info *ptr;
495     int flag;
496     if (!domain->is_deleted || domain->domainname != saved_domainname) continue;
497     flag = 0;
498     /***** CRITICAL SECTION START *****/
499     read_lock(&tasklist_lock);
500     for_each_process(p) {
501     if (p->domain_info == domain) { flag = 1; break; }
502     }
503     read_unlock(&tasklist_lock);
504     /***** CRITICAL SECTION END *****/
505     if (flag) continue;
506     #ifdef DEBUG_DOMAIN_UNDELETE
507     printk("Reusing %p %s\n", domain, domain->domainname->name);
508     #endif
509 kumaneko 722 list1_for_each_entry(ptr, &domain->acl_info_list, list) ptr->is_deleted = 1;
510 kumaneko 111 domain->profile = profile;
511     domain->quota_warned = 0;
512 kumaneko 708 mb(); /* Avoid out-of-order execution. */
513 kumaneko 111 domain->is_deleted = 0;
514     goto out;
515     }
516     /* No memory reusable. Create using new memory. */
517 kumaneko 214 if ((domain = alloc_element(sizeof(*domain))) != NULL) {
518 kumaneko 722 INIT_LIST1_HEAD(&domain->acl_info_list);
519 kumaneko 111 domain->domainname = saved_domainname;
520     domain->profile = profile;
521 kumaneko 722 list1_add_tail_mb(&domain->list, &domain_list);
522 kumaneko 111 }
523     out: ;
524 kumaneko 652 mutex_unlock(&new_domain_assign_lock);
525 kumaneko 111 return domain;
526     }
527    
528     static int Escape(char *dest, const char *src, int dest_len)
529     {
530     while (*src) {
531     const unsigned char c = * (const unsigned char *) src;
532     if (c == '\\') {
533     dest_len -= 2;
534     if (dest_len <= 0) goto out;
535     *dest++ = '\\';
536     *dest++ = '\\';
537     } else if (c > ' ' && c < 127) {
538     if (--dest_len <= 0) goto out;
539     *dest++ = c;
540     } else {
541     dest_len -= 4;
542     if (dest_len <= 0) goto out;
543     *dest++ = '\\';
544     *dest++ = (c >> 6) + '0';
545     *dest++ = ((c >> 3) & 7) + '0';
546     *dest++ = (c & 7) + '0';
547     }
548     src++;
549     }
550     if (--dest_len <= 0) goto out;
551     *dest = '\0';
552     return 0;
553     out:
554     return -ENOMEM;
555     }
556    
557 kumaneko 115 static char *get_argv0(struct linux_binprm *bprm)
558 kumaneko 111 {
559 kumaneko 316 char *arg_ptr = ccs_alloc(PAGE_SIZE); /* Initial buffer. */
560     int arg_len = 0;
561     unsigned long pos = bprm->p;
562     int i = pos / PAGE_SIZE, offset = pos % PAGE_SIZE;
563     if (!bprm->argc || !arg_ptr) goto out;
564     while (1) {
565     struct page *page;
566     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)
567     if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0) goto out;
568     #else
569     page = bprm->page[i];
570     #endif
571     { /* Map and copy to kernel buffer and unmap. */
572 kumaneko 115 const char *kaddr = kmap(page);
573 kumaneko 316 if (!kaddr) { /* Mapping failed. */
574     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)
575     put_page(page);
576     #endif
577     goto out;
578     }
579 kumaneko 115 memmove(arg_ptr + arg_len, kaddr + offset, PAGE_SIZE - offset);
580     kunmap(page);
581     }
582 kumaneko 316 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)
583     put_page(page);
584     pos += PAGE_SIZE - offset;
585     #endif
586     arg_len += PAGE_SIZE - offset;
587     if (memchr(arg_ptr, '\0', arg_len)) break;
588     { /* Initial buffer was too small for argv[0]. Retry after expanding buffer. */
589     char *tmp_arg_ptr = ccs_alloc(arg_len + PAGE_SIZE);
590     if (!tmp_arg_ptr) goto out;
591     memmove(tmp_arg_ptr, arg_ptr, arg_len);
592     ccs_free(arg_ptr);
593     arg_ptr = tmp_arg_ptr;
594     }
595     i++;
596     offset = 0;
597 kumaneko 115 }
598 kumaneko 316 return arg_ptr;
599     out: /* Release initial buffer. */
600     ccs_free(arg_ptr);
601 kumaneko 115 return NULL;
602     }
603    
604 kumaneko 708 static int FindNextDomain(struct linux_binprm *bprm, struct domain_info **next_domain, const u8 do_perm_check)
605 kumaneko 115 {
606 kumaneko 111 /* This function assumes that the size of buffer returned by realpath() = CCS_MAX_PATHNAME_LEN. */
607     struct domain_info *old_domain = current->domain_info, *domain = NULL;
608     const char *old_domain_name = old_domain->domainname->name;
609 kumaneko 115 const char *original_name = bprm->filename;
610     struct file *filp = bprm->file;
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     static int first = 1;
622     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     if ((retval = CheckExecPerm(&r, filp)) < 0) goto out;
693    
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     #else
758     page = bprm->page[i];
759 kumaneko 111 #endif
760 kumaneko 581 /* Map */
761     kaddr = kmap(page);
762     if (!kaddr) { /* Mapping failed. */
763     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)
764     put_page(page);
765     #endif
766     goto out;
767     }
768     /* Read. */
769     while (argv_count && offset < PAGE_SIZE) {
770     if (!kaddr[offset++]) argv_count--;
771     }
772     if (argv_count) goto unmap_page;
773     while (offset < PAGE_SIZE) {
774     const unsigned char c = kaddr[offset++];
775 kumaneko 652 if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
776 kumaneko 581 if (c == '=') {
777     arg_ptr[arg_len++] = '\0';
778     } else if (c == '\\') {
779     arg_ptr[arg_len++] = '\\';
780     arg_ptr[arg_len++] = '\\';
781     } else if (c > ' ' && c < 127) {
782     arg_ptr[arg_len++] = c;
783     } else {
784     arg_ptr[arg_len++] = '\\';
785     arg_ptr[arg_len++] = (c >> 6) + '0';
786     arg_ptr[arg_len++] = ((c >> 3) & 7) + '0';
787     arg_ptr[arg_len++] = (c & 7) + '0';
788     }
789     } else {
790     arg_ptr[arg_len] = '\0';
791     }
792     if (c) continue;
793 kumaneko 815 if (CheckEnvPerm(arg_ptr, profile, mode)) {
794 kumaneko 581 error = -EPERM;
795     break;
796     }
797     if (!--envp_count) {
798     error = 0;
799     break;
800     }
801     arg_len = 0;
802     }
803     unmap_page:
804     /* Unmap. */
805     kunmap(page);
806     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)
807     put_page(page);
808     pos += PAGE_SIZE - offset;
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     static int try_alt_exec(struct linux_binprm *bprm, char **alt_exec0)
843     {
844     struct file *filp;
845     int retval;
846     /* domainname must not be modified. */
847     char *domainname = (char *) current->domain_info->domainname->name;
848     char *alt_exec;
849     const char *alt_exec1 = GetAltExec();
850     if (!alt_exec1 || *alt_exec1 != '/') return -EINVAL;
851     retval = strlen(alt_exec1) + 1;
852     *alt_exec0 = alt_exec = ccs_alloc(retval);
853     if (!alt_exec) return -ENOMEM;
854     memmove(alt_exec, alt_exec1, retval);
855     UnEscape(alt_exec);
856     allow_write_access(bprm->file);
857     fput(bprm->file);
858     bprm->file = NULL;
859     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
860     retval = remove_arg_zero(bprm);
861     if (retval) return retval;
862     #else
863     remove_arg_zero(bprm);
864 kumaneko 581 #endif
865 kumaneko 708 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
866     retval = copy_strings_kernel(1, &bprm->interp, bprm);
867     #else
868     retval = copy_strings_kernel(1, &bprm->filename, bprm);
869     #endif
870     if (retval < 0) return retval;
871     bprm->argc++;
872     retval = copy_strings_kernel(1, &domainname, bprm);
873     if (retval < 0) return retval;
874     bprm->argc++;
875     retval = copy_strings_kernel(1, &alt_exec, bprm);
876     if (retval < 0) return retval;
877     bprm->argc++;
878     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
879     bprm->interp = alt_exec;
880     #endif
881     filp = open_exec(alt_exec);
882     if (IS_ERR(filp)) return PTR_ERR(filp);
883     bprm->file= filp;
884     bprm->filename = alt_exec;
885     return prepare_binprm(bprm);
886     }
887 kumaneko 581
888 kumaneko 708 #endif
889    
890 kumaneko 115 int search_binary_handler_with_transition(struct linux_binprm *bprm, struct pt_regs *regs)
891     {
892     struct domain_info *next_domain = NULL, *prev_domain = current->domain_info;
893     int retval;
894 kumaneko 708 char *alt_exec = NULL; /* Keep valid until search_binary_handler() finishes. */
895 kumaneko 115 #if defined(CONFIG_SAKURA) || defined(CONFIG_TOMOYO)
896     extern void CCS_LoadPolicy(const char *filename);
897     CCS_LoadPolicy(bprm->filename);
898     #endif
899     #if defined(CONFIG_TOMOYO)
900 kumaneko 708 retval = FindNextDomain(bprm, &next_domain, 1);
901     if (retval == -EPERM && try_alt_exec(bprm, &alt_exec) >= 0) {
902     current->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
903     retval = FindNextDomain(bprm, &next_domain, 0);
904     current->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
905     }
906 kumaneko 115 if (retval == 0) {
907 kumaneko 581 current->domain_info = next_domain;
908 kumaneko 816 retval = CheckEnviron(bprm);
909 kumaneko 115 current->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
910 kumaneko 581 if (!retval) retval = search_binary_handler(bprm, regs);
911     current->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
912 kumaneko 115 if (retval < 0) current->domain_info = prev_domain;
913     }
914 kumaneko 708 ccs_free(alt_exec);
915 kumaneko 815 return retval;
916     #else
917     return search_binary_handler(bprm, regs);
918 kumaneko 722 #endif
919 kumaneko 115 }
920    
921 kumaneko 111 /***** TOMOYO Linux end. *****/

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