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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3747 - (hide annotations) (download) (as text)
Wed Jun 9 13:58:57 2010 UTC (13 years, 11 months ago) by kumaneko
Original Path: branches/ccs-patch/security/ccsecurity/domain.c
File MIME type: text/x-csrc
File size: 35714 byte(s)


1 kumaneko 111 /*
2 kumaneko 2864 * security/ccsecurity/domain.c
3 kumaneko 111 *
4 kumaneko 3360 * Copyright (C) 2005-2010 NTT DATA CORPORATION
5 kumaneko 111 *
6 kumaneko 3731 * Version: 1.7.2+ 2010/06/04
7 kumaneko 111 *
8     * This file is applicable to both 2.4.30 and 2.6.11 and later.
9     * See README.ccs for ChangeLog.
10     *
11     */
12    
13 kumaneko 2763 #include <linux/slab.h>
14 kumaneko 115 #include <linux/highmem.h>
15 kumaneko 2763 #include <linux/version.h>
16 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
17     #include <linux/namei.h>
18     #include <linux/mount.h>
19     #endif
20 kumaneko 2402 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
21     #include <linux/fs_struct.h>
22     #endif
23 kumaneko 2854 #include "internal.h"
24 kumaneko 115
25 kumaneko 1052 /* Variables definitions.*/
26 kumaneko 111
27 kumaneko 3697 /* The global domain. */
28     struct ccs_domain_info ccs_global_domain;
29    
30 kumaneko 111 /* The initial domain. */
31 kumaneko 2282 struct ccs_domain_info ccs_kernel_domain;
32 kumaneko 111
33 kumaneko 2282 /* The list for "struct ccs_domain_info". */
34 kumaneko 2540 LIST_HEAD(ccs_domain_list);
35 kumaneko 708
36 kumaneko 3689 struct list_head ccs_policy_list[CCS_MAX_POLICY];
37     struct list_head ccs_group_list[CCS_MAX_GROUP];
38     struct list_head ccs_shared_list[CCS_MAX_LIST];
39    
40 kumaneko 1052 /**
41 kumaneko 2002 * ccs_audit_execute_handler_log - Audit execute_handler log.
42 kumaneko 1052 *
43 kumaneko 3693 * @ee: Pointer to "struct ccs_execve".
44 kumaneko 1052 *
45     * Returns 0 on success, negative value otherwise.
46     */
47 kumaneko 3693 static int ccs_audit_execute_handler_log(struct ccs_execve *ee)
48 kumaneko 1052 {
49 kumaneko 2037 struct ccs_request_info *r = &ee->r;
50     const char *handler = ee->handler->name;
51 kumaneko 3626 r->type = CCS_MAC_FILE_EXECUTE;
52 kumaneko 2943 r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);
53 kumaneko 3701 r->granted = true;
54     return ccs_write_log(r, "%s %s\n", ee->handler_type ==
55 kumaneko 3694 CCS_TYPE_DENIED_EXECUTE_HANDLER ?
56     CCS_KEYWORD_DENIED_EXECUTE_HANDLER :
57     CCS_KEYWORD_EXECUTE_HANDLER, handler);
58 kumaneko 1052 }
59 kumaneko 111
60 kumaneko 1052 /**
61 kumaneko 2002 * ccs_audit_domain_creation_log - Audit domain creation log.
62 kumaneko 1052 *
63     * Returns 0 on success, negative value otherwise.
64     */
65 kumaneko 3627 static int ccs_audit_domain_creation_log(void)
66 kumaneko 1052 {
67 kumaneko 1657 struct ccs_request_info r;
68 kumaneko 3627 ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
69 kumaneko 3701 r.granted = false;
70     return ccs_write_log(&r, "use_profile %u\n", r.profile);
71 kumaneko 1052 }
72    
73 kumaneko 3689 int ccs_update_policy(struct ccs_acl_head *new_entry, const int size,
74     bool is_delete, const int idx, bool (*check_duplicate)
75     (const struct ccs_acl_head *,
76     const struct ccs_acl_head *))
77     {
78     int error = is_delete ? -ENOENT : -ENOMEM;
79     struct ccs_acl_head *entry;
80     if (mutex_lock_interruptible(&ccs_policy_lock))
81     return -ENOMEM;
82     list_for_each_entry_rcu(entry, &ccs_policy_list[idx], list) {
83     if (!check_duplicate(entry, new_entry))
84     continue;
85     entry->is_deleted = is_delete;
86     error = 0;
87     break;
88     }
89     if (error && !is_delete) {
90     entry = ccs_commit_ok(new_entry, size);
91     if (entry) {
92     list_add_tail_rcu(&entry->list, &ccs_policy_list[idx]);
93     error = 0;
94     }
95     }
96     mutex_unlock(&ccs_policy_lock);
97     return error;
98     }
99 kumaneko 111
100 kumaneko 3689 int ccs_update_group(struct ccs_acl_head *new_entry, const int size,
101     bool is_delete, struct ccs_group *group,
102     bool (*check_duplicate) (const struct ccs_acl_head *,
103     const struct ccs_acl_head *))
104     {
105     int error = is_delete ? -ENOENT : -ENOMEM;
106     struct ccs_acl_head *entry;
107     if (mutex_lock_interruptible(&ccs_policy_lock))
108     return -ENOMEM;
109     list_for_each_entry_rcu(entry, &group->member_list, list) {
110     if (!check_duplicate(entry, new_entry))
111     continue;
112     entry->is_deleted = is_delete;
113     error = 0;
114     break;
115     }
116     if (!is_delete && error) {
117     entry = ccs_commit_ok(new_entry, size);
118     if (entry) {
119     list_add_tail_rcu(&entry->list, &group->member_list);
120     error = 0;
121     }
122     }
123     mutex_unlock(&ccs_policy_lock);
124     return error;
125     }
126    
127 kumaneko 3697 static void ccs_delete_type(struct ccs_domain_info *domain, u8 type)
128     {
129     struct ccs_acl_info *ptr;
130     list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
131     if (ptr->type == type)
132     ptr->is_deleted = true;
133     }
134     }
135    
136 kumaneko 3693 int ccs_update_domain(struct ccs_acl_info *new_entry, const int size,
137     bool is_delete, struct ccs_domain_info *domain,
138     bool (*check_duplicate) (const struct ccs_acl_info *,
139     const struct ccs_acl_info *),
140     bool (*merge_duplicate) (struct ccs_acl_info *,
141     struct ccs_acl_info *,
142     const bool))
143 kumaneko 3689 {
144     int error = is_delete ? -ENOENT : -ENOMEM;
145     struct ccs_acl_info *entry;
146 kumaneko 3697 /*
147     * Only one "execute_handler" and "denied_execute_handler" can exist
148     * in a domain.
149     */
150     const u8 type = new_entry->type;
151     const bool exclusive = !is_delete &&
152     (type == CCS_TYPE_EXECUTE_HANDLER ||
153     type == CCS_TYPE_DENIED_EXECUTE_HANDLER);
154 kumaneko 3689 if (mutex_lock_interruptible(&ccs_policy_lock))
155     return error;
156     list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
157     if (!check_duplicate(entry, new_entry))
158     continue;
159 kumaneko 3697 if (exclusive)
160     ccs_delete_type(domain, type);
161 kumaneko 3689 if (merge_duplicate)
162     entry->is_deleted = merge_duplicate(entry, new_entry,
163     is_delete);
164     else
165     entry->is_deleted = is_delete;
166     error = 0;
167     break;
168     }
169     if (error && !is_delete) {
170     entry = ccs_commit_ok(new_entry, size);
171     if (entry) {
172 kumaneko 3697 if (exclusive)
173     ccs_delete_type(domain, type);
174 kumaneko 3689 ccs_add_domain_acl(domain, entry);
175     error = 0;
176     }
177     }
178     mutex_unlock(&ccs_policy_lock);
179     return error;
180     }
181    
182 kumaneko 3701 void ccs_check_acl(struct ccs_request_info *r,
183     bool (*check_entry) (const struct ccs_request_info *,
184     const struct ccs_acl_info *))
185     {
186     const struct ccs_domain_info *domain = ccs_current_domain();
187     struct ccs_acl_info *ptr;
188     retry:
189     list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
190     if (ptr->is_deleted || ptr->type != r->param_type)
191     continue;
192     if (check_entry(r, ptr) && ccs_condition(r, ptr->cond)) {
193     r->cond = ptr->cond;
194     r->granted = true;
195     return;
196     }
197     }
198 kumaneko 3747 if (domain != &ccs_global_domain && !domain->flags[CCS_DIF_IGNORE_GLOBAL] &&
199 kumaneko 3701 (r->param_type != CCS_TYPE_PATH_ACL ||
200     r->param.path.operation != CCS_TYPE_READ ||
201 kumaneko 3747 !domain->flags[CCS_DIF_IGNORE_GLOBAL_ALLOW_READ]) &&
202 kumaneko 3701 (r->param_type != CCS_TYPE_ENV_ACL ||
203 kumaneko 3747 !domain->flags[CCS_DIF_IGNORE_GLOBAL_ALLOW_ENV])) {
204 kumaneko 3701 domain = &ccs_global_domain;
205     goto retry;
206     }
207     r->granted = false;
208     }
209    
210 kumaneko 3693 static bool ccs_same_domain_initializer_entry(const struct ccs_acl_head *a,
211 kumaneko 3695 const struct ccs_acl_head *b)
212 kumaneko 3689 {
213 kumaneko 3695 const struct ccs_domain_initializer *p1 = container_of(a, typeof(*p1),
214     head);
215     const struct ccs_domain_initializer *p2 = container_of(b, typeof(*p2),
216     head);
217 kumaneko 3689 return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
218     && p1->domainname == p2->domainname
219     && p1->program == p2->program;
220     }
221    
222 kumaneko 1052 /**
223 kumaneko 3693 * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer" list.
224 kumaneko 1052 *
225     * @domainname: The name of domain. May be NULL.
226     * @program: The name of program.
227     * @is_not: True if it is "no_initialize_domain" entry.
228     * @is_delete: True if it is a delete request.
229     *
230     * Returns 0 on success, negative value otherwise.
231     */
232 kumaneko 2002 static int ccs_update_domain_initializer_entry(const char *domainname,
233     const char *program,
234     const bool is_not,
235     const bool is_delete)
236 kumaneko 111 {
237 kumaneko 3693 struct ccs_domain_initializer e = { .is_not = is_not };
238 kumaneko 2540 int error = is_delete ? -ENOENT : -ENOMEM;
239 kumaneko 3707 if (!ccs_correct_path(program))
240     return -EINVAL;
241 kumaneko 111 if (domainname) {
242 kumaneko 3693 if (!ccs_domain_def(domainname) &&
243 kumaneko 3707 ccs_correct_path(domainname))
244 kumaneko 2900 e.is_last_name = true;
245 kumaneko 3693 else if (!ccs_correct_domain(domainname))
246 kumaneko 111 return -EINVAL;
247 kumaneko 2900 e.domainname = ccs_get_name(domainname);
248     if (!e.domainname)
249     goto out;
250 kumaneko 111 }
251 kumaneko 2900 e.program = ccs_get_name(program);
252     if (!e.program)
253     goto out;
254 kumaneko 3689 error = ccs_update_policy(&e.head, sizeof(e), is_delete,
255     CCS_ID_DOMAIN_INITIALIZER,
256 kumaneko 3693 ccs_same_domain_initializer_entry);
257 kumaneko 2900 out:
258     ccs_put_name(e.domainname);
259     ccs_put_name(e.program);
260 kumaneko 111 return error;
261     }
262    
263 kumaneko 1052 /**
264 kumaneko 3693 * ccs_write_domain_initializer - Write "struct ccs_domain_initializer" list.
265 kumaneko 1052 *
266     * @data: String to parse.
267     * @is_delete: True if it is a delete request.
268     *
269     * Returns 0 on success, negative value otherwise.
270     */
271 kumaneko 3693 int ccs_write_domain_initializer(char *data, const bool is_delete, const u8 flags)
272 kumaneko 111 {
273 kumaneko 3691 char *domainname = strstr(data, " from ");
274     if (domainname) {
275     *domainname = '\0';
276     domainname += 6;
277 kumaneko 111 }
278 kumaneko 3691 return ccs_update_domain_initializer_entry(domainname, data, flags,
279 kumaneko 2002 is_delete);
280 kumaneko 111 }
281    
282 kumaneko 1052 /**
283 kumaneko 3693 * ccs_domain_initializer - Check whether the given program causes domainname reinitialization.
284 kumaneko 1052 *
285     * @domainname: The name of domain.
286     * @program: The name of program.
287     * @last_name: The last component of @domainname.
288     *
289     * Returns true if executing @program reinitializes domain transition,
290     * false otherwise.
291 kumaneko 2690 *
292 kumaneko 2828 * Caller holds ccs_read_lock().
293 kumaneko 1052 */
294 kumaneko 3693 static bool ccs_domain_initializer(const struct ccs_path_info *domainname,
295 kumaneko 2002 const struct ccs_path_info *program,
296     const struct ccs_path_info *last_name)
297 kumaneko 111 {
298 kumaneko 3693 struct ccs_domain_initializer *ptr;
299 kumaneko 1016 bool flag = false;
300 kumaneko 3689 list_for_each_entry_rcu(ptr, &ccs_policy_list
301     [CCS_ID_DOMAIN_INITIALIZER], head.list) {
302     if (ptr->head.is_deleted)
303 kumaneko 1052 continue;
304 kumaneko 111 if (ptr->domainname) {
305     if (!ptr->is_last_name) {
306 kumaneko 1052 if (ptr->domainname != domainname)
307     continue;
308 kumaneko 111 } else {
309 kumaneko 1052 if (ccs_pathcmp(ptr->domainname, last_name))
310     continue;
311 kumaneko 111 }
312     }
313 kumaneko 1052 if (ccs_pathcmp(ptr->program, program))
314     continue;
315 kumaneko 2540 if (ptr->is_not) {
316     flag = false;
317     break;
318     }
319 kumaneko 1016 flag = true;
320 kumaneko 111 }
321     return flag;
322     }
323    
324 kumaneko 3693 static bool ccs_same_domain_keeper_entry(const struct ccs_acl_head *a,
325 kumaneko 3695 const struct ccs_acl_head *b)
326 kumaneko 3689 {
327 kumaneko 3695 const struct ccs_domain_keeper *p1 = container_of(a, typeof(*p1),
328     head);
329     const struct ccs_domain_keeper *p2 = container_of(b, typeof(*p2),
330     head);
331 kumaneko 3689 return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
332     && p1->domainname == p2->domainname
333     && p1->program == p2->program;
334     }
335 kumaneko 111
336 kumaneko 1052 /**
337 kumaneko 3693 * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper" list.
338 kumaneko 1052 *
339     * @domainname: The name of domain.
340     * @program: The name of program. May be NULL.
341     * @is_not: True if it is "no_keep_domain" entry.
342     * @is_delete: True if it is a delete request.
343     *
344     * Returns 0 on success, negative value otherwise.
345     */
346 kumaneko 2002 static int ccs_update_domain_keeper_entry(const char *domainname,
347     const char *program,
348     const bool is_not,
349     const bool is_delete)
350 kumaneko 111 {
351 kumaneko 3693 struct ccs_domain_keeper e = { .is_not = is_not };
352 kumaneko 2540 int error = is_delete ? -ENOENT : -ENOMEM;
353 kumaneko 3707 if (!ccs_domain_def(domainname) && ccs_correct_path(domainname))
354 kumaneko 2900 e.is_last_name = true;
355 kumaneko 3693 else if (!ccs_correct_domain(domainname))
356 kumaneko 111 return -EINVAL;
357     if (program) {
358 kumaneko 3707 if (!ccs_correct_path(program))
359 kumaneko 1052 return -EINVAL;
360 kumaneko 2900 e.program = ccs_get_name(program);
361     if (!e.program)
362     goto out;
363 kumaneko 111 }
364 kumaneko 2900 e.domainname = ccs_get_name(domainname);
365     if (!e.domainname)
366     goto out;
367 kumaneko 3689 error = ccs_update_policy(&e.head, sizeof(e), is_delete,
368     CCS_ID_DOMAIN_KEEPER,
369 kumaneko 3693 ccs_same_domain_keeper_entry);
370 kumaneko 2900 out:
371     ccs_put_name(e.domainname);
372     ccs_put_name(e.program);
373 kumaneko 111 return error;
374     }
375    
376 kumaneko 1052 /**
377 kumaneko 3693 * ccs_write_domain_keeper - Write "struct ccs_domain_keeper" list.
378 kumaneko 1052 *
379     * @data: String to parse.
380     * @is_delete: True if it is a delete request.
381     *
382 kumaneko 3691 * Returns 0 on success, negative value otherwise.
383 kumaneko 1052 */
384 kumaneko 3693 int ccs_write_domain_keeper(char *data, const bool is_delete, const u8 flags)
385 kumaneko 111 {
386 kumaneko 3691 char *domainname = strstr(data, " from ");
387     if (domainname) {
388     *domainname = '\0';
389     domainname += 6;
390     } else {
391     domainname = data;
392     data = NULL;
393 kumaneko 111 }
394 kumaneko 3691 return ccs_update_domain_keeper_entry(domainname, data, flags,
395     is_delete);
396 kumaneko 111 }
397    
398 kumaneko 1052 /**
399 kumaneko 3693 * ccs_domain_keeper - Check whether the given program causes domain transition suppression.
400 kumaneko 1052 *
401     * @domainname: The name of domain.
402     * @program: The name of program.
403     * @last_name: The last component of @domainname.
404     *
405     * Returns true if executing @program supresses domain transition,
406     * false otherwise.
407 kumaneko 2690 *
408 kumaneko 2828 * Caller holds ccs_read_lock().
409 kumaneko 1052 */
410 kumaneko 3693 static bool ccs_domain_keeper(const struct ccs_path_info *domainname,
411 kumaneko 2002 const struct ccs_path_info *program,
412     const struct ccs_path_info *last_name)
413 kumaneko 111 {
414 kumaneko 3693 struct ccs_domain_keeper *ptr;
415 kumaneko 1016 bool flag = false;
416 kumaneko 3689 list_for_each_entry_rcu(ptr, &ccs_policy_list[CCS_ID_DOMAIN_KEEPER],
417     head.list) {
418     if (ptr->head.is_deleted)
419 kumaneko 1052 continue;
420 kumaneko 111 if (!ptr->is_last_name) {
421 kumaneko 1052 if (ptr->domainname != domainname)
422     continue;
423 kumaneko 111 } else {
424 kumaneko 1052 if (ccs_pathcmp(ptr->domainname, last_name))
425     continue;
426 kumaneko 111 }
427 kumaneko 1052 if (ptr->program && ccs_pathcmp(ptr->program, program))
428     continue;
429 kumaneko 2540 if (ptr->is_not) {
430     flag = false;
431     break;
432     }
433 kumaneko 1016 flag = true;
434 kumaneko 111 }
435     return flag;
436     }
437    
438 kumaneko 3693 static bool ccs_same_aggregator_entry(const struct ccs_acl_head *a,
439 kumaneko 3695 const struct ccs_acl_head *b)
440 kumaneko 3689 {
441 kumaneko 3695 const struct ccs_aggregator *p1 = container_of(a, typeof(*p1), head);
442     const struct ccs_aggregator *p2 = container_of(b, typeof(*p2), head);
443 kumaneko 3689 return p1->original_name == p2->original_name &&
444     p1->aggregated_name == p2->aggregated_name;
445     }
446 kumaneko 111
447 kumaneko 1052 /**
448 kumaneko 3693 * ccs_update_aggregator_entry - Update "struct ccs_aggregator" list.
449 kumaneko 1052 *
450     * @original_name: The original program's name.
451     * @aggregated_name: The aggregated program's name.
452     * @is_delete: True if it is a delete request.
453     *
454     * Returns 0 on success, negative value otherwise.
455     */
456 kumaneko 2002 static int ccs_update_aggregator_entry(const char *original_name,
457     const char *aggregated_name,
458     const bool is_delete)
459 kumaneko 111 {
460 kumaneko 3693 struct ccs_aggregator e = { };
461 kumaneko 2540 int error = is_delete ? -ENOENT : -ENOMEM;
462 kumaneko 3707 if (!ccs_correct_path(original_name) ||
463     !ccs_correct_path(aggregated_name))
464 kumaneko 1052 return -EINVAL;
465 kumaneko 2900 e.original_name = ccs_get_name(original_name);
466     e.aggregated_name = ccs_get_name(aggregated_name);
467 kumaneko 3710 if (!e.original_name || !e.aggregated_name ||
468     e.aggregated_name->is_patterned) /* No patterns allowed. */
469 kumaneko 2900 goto out;
470 kumaneko 3689 error = ccs_update_policy(&e.head, sizeof(e), is_delete,
471     CCS_ID_AGGREGATOR,
472 kumaneko 3693 ccs_same_aggregator_entry);
473 kumaneko 2900 out:
474     ccs_put_name(e.original_name);
475     ccs_put_name(e.aggregated_name);
476 kumaneko 111 return error;
477     }
478    
479 kumaneko 1052 /**
480 kumaneko 3693 * ccs_write_aggregator - Write "struct ccs_aggregator" list.
481 kumaneko 1052 *
482     * @data: String to parse.
483     * @is_delete: True if it is a delete request.
484     *
485     * Returns 0 on success, negative value otherwise.
486     */
487 kumaneko 3693 int ccs_write_aggregator(char *data, const bool is_delete, const u8 flags)
488 kumaneko 111 {
489 kumaneko 2779 char *w[2];
490     if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
491 kumaneko 2870 return -EINVAL;
492 kumaneko 2779 return ccs_update_aggregator_entry(w[0], w[1], is_delete);
493 kumaneko 111 }
494    
495 kumaneko 2393 /* Domain create/delete handler. */
496 kumaneko 111
497 kumaneko 1052 /**
498     * ccs_delete_domain - Delete a domain.
499     *
500     * @domainname: The name of domain.
501     *
502     * Returns 0.
503     */
504     int ccs_delete_domain(char *domainname)
505 kumaneko 111 {
506 kumaneko 2282 struct ccs_domain_info *domain;
507 kumaneko 2002 struct ccs_path_info name;
508 kumaneko 1052 name.name = domainname;
509     ccs_fill_path_info(&name);
510 kumaneko 3534 if (mutex_lock_interruptible(&ccs_policy_lock))
511     return 0;
512 kumaneko 111 /* Is there an active domain? */
513 kumaneko 2690 list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
514 kumaneko 2282 /* Never delete ccs_kernel_domain */
515     if (domain == &ccs_kernel_domain)
516 kumaneko 1052 continue;
517     if (domain->is_deleted ||
518     ccs_pathcmp(domain->domainname, &name))
519     continue;
520 kumaneko 2393 domain->is_deleted = true;
521 kumaneko 708 break;
522 kumaneko 111 }
523 kumaneko 2690 mutex_unlock(&ccs_policy_lock);
524 kumaneko 111 return 0;
525     }
526    
527 kumaneko 1052 /**
528 kumaneko 3694 * ccs_assign_domain - Create a domain.
529 kumaneko 1052 *
530     * @domainname: The name of domain.
531     * @profile: Profile number to assign if the domain was newly created.
532     *
533 kumaneko 2690 * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
534 kumaneko 1052 */
535 kumaneko 3694 struct ccs_domain_info *ccs_assign_domain(const char *domainname,
536     const u8 profile)
537 kumaneko 111 {
538 kumaneko 3697 struct ccs_domain_info e = { };
539     struct ccs_domain_info *entry = NULL;
540 kumaneko 2690 bool found = false;
541 kumaneko 2870
542 kumaneko 3693 if (!ccs_correct_domain(domainname))
543 kumaneko 2690 return NULL;
544 kumaneko 3697 e.profile = profile;
545     e.domainname = ccs_get_name(domainname);
546     if (!e.domainname)
547 kumaneko 2690 return NULL;
548 kumaneko 3534 if (mutex_lock_interruptible(&ccs_policy_lock))
549     goto out;
550 kumaneko 3697 list_for_each_entry_rcu(entry, &ccs_domain_list, list) {
551     if (entry->is_deleted ||
552     ccs_pathcmp(e.domainname, entry->domainname))
553 kumaneko 2544 continue;
554 kumaneko 2690 found = true;
555 kumaneko 2544 break;
556 kumaneko 111 }
557 kumaneko 3697 if (!found) {
558     entry = ccs_commit_ok(&e, sizeof(e));
559     if (entry) {
560     INIT_LIST_HEAD(&entry->acl_info_list);
561     list_add_tail_rcu(&entry->list, &ccs_domain_list);
562     found = true;
563     }
564 kumaneko 2544 }
565 kumaneko 2690 mutex_unlock(&ccs_policy_lock);
566 kumaneko 3534 out:
567 kumaneko 3697 ccs_put_name(e.domainname);
568     return found ? entry : NULL;
569 kumaneko 111 }
570    
571 kumaneko 1052 /**
572 kumaneko 2002 * ccs_find_next_domain - Find a domain.
573 kumaneko 1052 *
574 kumaneko 3693 * @ee: Pointer to "struct ccs_execve".
575 kumaneko 1052 *
576     * Returns 0 on success, negative value otherwise.
577 kumaneko 2690 *
578 kumaneko 2828 * Caller holds ccs_read_lock().
579 kumaneko 1052 */
580 kumaneko 3693 static int ccs_find_next_domain(struct ccs_execve *ee)
581 kumaneko 115 {
582 kumaneko 2037 struct ccs_request_info *r = &ee->r;
583     const struct ccs_path_info *handler = ee->handler;
584 kumaneko 2691 struct ccs_domain_info *domain = NULL;
585 kumaneko 3627 struct ccs_domain_info * const old_domain = ccs_current_domain();
586     const char *old_domain_name = old_domain->domainname->name;
587 kumaneko 2037 struct linux_binprm *bprm = ee->bprm;
588 kumaneko 3627 struct task_struct *task = current;
589     const u32 ccs_flags = task->ccs_flags;
590 kumaneko 2932 struct ccs_path_info rn = { }; /* real name */
591 kumaneko 2002 struct ccs_path_info ln; /* last name */
592 kumaneko 111 int retval;
593 kumaneko 2932 bool need_kfree = false;
594 kumaneko 3627 bool domain_created = false;
595 kumaneko 2943 ln.name = ccs_last_word(old_domain_name);
596     ccs_fill_path_info(&ln);
597 kumaneko 1561 retry:
598 kumaneko 2282 current->ccs_flags = ccs_flags;
599 kumaneko 2690 r->cond = NULL;
600 kumaneko 2943 if (need_kfree) {
601     kfree(rn.name);
602     need_kfree = false;
603     }
604    
605 kumaneko 2738 /* Get symlink's pathname of program. */
606 kumaneko 2932 retval = ccs_symlink_path(bprm->filename, &rn);
607 kumaneko 2075 if (retval < 0)
608 kumaneko 1052 goto out;
609 kumaneko 2932 need_kfree = true;
610 kumaneko 111
611 kumaneko 1657 if (handler) {
612     if (ccs_pathcmp(&rn, handler)) {
613 kumaneko 1064 /* Failed to verify execute handler. */
614 kumaneko 1029 static u8 counter = 20;
615     if (counter) {
616     counter--;
617 kumaneko 1052 printk(KERN_WARNING "Failed to verify: %s\n",
618 kumaneko 1657 handler->name);
619 kumaneko 1029 }
620     goto out;
621     }
622 kumaneko 2943 } else {
623 kumaneko 3693 struct ccs_aggregator *ptr;
624 kumaneko 2943 /* Check 'aggregator' directive. */
625 kumaneko 3689 list_for_each_entry_rcu(ptr,
626     &ccs_policy_list[CCS_ID_AGGREGATOR],
627     head.list) {
628     if (ptr->head.is_deleted ||
629 kumaneko 1657 !ccs_path_matches_pattern(&rn, ptr->original_name))
630 kumaneko 1052 continue;
631 kumaneko 2932 kfree(rn.name);
632     need_kfree = false;
633 kumaneko 2943 /* This is OK because it is read only. */
634 kumaneko 2932 rn = *ptr->aggregated_name;
635 kumaneko 183 break;
636     }
637 kumaneko 2943
638     /* Check execute permission. */
639 kumaneko 3701 retval = ccs_path_permission(r, CCS_TYPE_EXECUTE, &rn);
640 kumaneko 3494 if (retval == CCS_RETRY_REQUEST)
641 kumaneko 2943 goto retry;
642     if (retval < 0)
643     goto out;
644 kumaneko 183 }
645    
646 kumaneko 2943 /* Calculate domain to transit to. */
647 kumaneko 3693 if (ccs_domain_initializer(old_domain->domainname, &rn, &ln)) {
648 kumaneko 2282 /* Transit to the child of ccs_kernel_domain domain. */
649 kumaneko 3707 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, CCS_ROOT_NAME " " "%s",
650 kumaneko 2932 rn.name);
651 kumaneko 3627 } else if (old_domain == &ccs_kernel_domain && !ccs_policy_loaded) {
652 kumaneko 111 /*
653 kumaneko 1052 * Needn't to transit from kernel domain before starting
654 kumaneko 1064 * /sbin/init. But transit from kernel domain if executing
655     * initializers because they might start before /sbin/init.
656 kumaneko 111 */
657 kumaneko 3627 domain = old_domain;
658 kumaneko 3693 } else if (ccs_domain_keeper(old_domain->domainname, &rn, &ln)) {
659 kumaneko 111 /* Keep current domain. */
660 kumaneko 3627 domain = old_domain;
661 kumaneko 111 } else {
662     /* Normal domain transition. */
663 kumaneko 2932 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
664     old_domain_name, rn.name);
665 kumaneko 111 }
666 kumaneko 2932 if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)
667 kumaneko 1052 goto done;
668 kumaneko 2932 domain = ccs_find_domain(ee->tmp);
669 kumaneko 2690 if (domain)
670 kumaneko 1052 goto done;
671 kumaneko 2958 if (r->mode == CCS_CONFIG_ENFORCING) {
672 kumaneko 2932 int error = ccs_supervisor(r, "# wants to create domain\n"
673     "%s\n", ee->tmp);
674 kumaneko 3494 if (error == CCS_RETRY_REQUEST)
675 kumaneko 1561 goto retry;
676     if (error < 0)
677 kumaneko 1052 goto done;
678 kumaneko 1561 }
679 kumaneko 3694 domain = ccs_assign_domain(ee->tmp, r->profile);
680 kumaneko 2690 if (domain)
681 kumaneko 3627 domain_created = true;
682 kumaneko 1052 done:
683 kumaneko 2691 if (!domain) {
684 kumaneko 3258 retval = (r->mode == CCS_CONFIG_ENFORCING) ? -EPERM : 0;
685 kumaneko 3747 if (!old_domain->flags[CCS_DIF_TRANSITION_FAILED]) {
686     old_domain->flags[CCS_DIF_TRANSITION_FAILED] = true;
687 kumaneko 3701 r->granted = false;
688     ccs_write_log(r, CCS_KEYWORD_TRANSITION_FAILED "\n");
689 kumaneko 3694 printk(KERN_WARNING
690     "ERROR: Domain '%s' not defined.\n", ee->tmp);
691 kumaneko 2691 }
692     } else {
693 kumaneko 111 retval = 0;
694     }
695 kumaneko 3627 if (!retval && handler)
696     ccs_audit_execute_handler_log(ee);
697     /*
698     * Tell GC that I started execve().
699     * Also, tell open_exec() to check read permission.
700     */
701     task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
702     /*
703     * Make task->ccs_flags visible to GC before changing
704     * task->ccs_domain_info .
705     */
706     smp_mb();
707     /*
708     * Proceed to the next domain in order to allow reaching via PID.
709     * It will be reverted if execve() failed. Reverting is not good.
710     * But it is better than being unable to reach via PID in interactive
711     * enforcing mode.
712     */
713     if (domain)
714     task->ccs_domain_info = domain;
715     if (domain_created)
716     ccs_audit_domain_creation_log();
717 kumaneko 1052 out:
718 kumaneko 2932 if (need_kfree)
719     kfree(rn.name);
720 kumaneko 111 return retval;
721     }
722    
723 kumaneko 1052 /**
724 kumaneko 2922 * ccs_environ - Check permission for environment variable names.
725 kumaneko 1052 *
726 kumaneko 3693 * @ee: Pointer to "struct ccs_execve".
727 kumaneko 1052 *
728     * Returns 0 on success, negative value otherwise.
729     */
730 kumaneko 3693 static int ccs_environ(struct ccs_execve *ee)
731 kumaneko 581 {
732 kumaneko 2037 struct ccs_request_info *r = &ee->r;
733     struct linux_binprm *bprm = ee->bprm;
734 kumaneko 3128 /* env_page->data is allocated by ccs_dump_page(). */
735     struct ccs_page_dump env_page = { };
736     char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
737 kumaneko 581 int arg_len = 0;
738     unsigned long pos = bprm->p;
739 kumaneko 1064 int offset = pos % PAGE_SIZE;
740 kumaneko 581 int argv_count = bprm->argc;
741     int envp_count = bprm->envc;
742 kumaneko 1052 /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
743 kumaneko 581 int error = -ENOMEM;
744 kumaneko 3627 ee->r.type = CCS_MAC_ENVIRON;
745     ee->r.mode = ccs_get_mode(ccs_current_domain()->profile,
746     CCS_MAC_ENVIRON);
747 kumaneko 1657 if (!r->mode || !envp_count)
748 kumaneko 1052 return 0;
749 kumaneko 3512 arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
750 kumaneko 3128 if (!arg_ptr)
751     goto out;
752 kumaneko 581 while (error == -ENOMEM) {
753 kumaneko 3128 if (!ccs_dump_page(bprm, pos, &env_page))
754 kumaneko 1052 goto out;
755 kumaneko 986 pos += PAGE_SIZE - offset;
756 kumaneko 581 /* Read. */
757     while (argv_count && offset < PAGE_SIZE) {
758 kumaneko 3128 if (!env_page.data[offset++])
759 kumaneko 1052 argv_count--;
760 kumaneko 581 }
761 kumaneko 2037 if (argv_count) {
762     offset = 0;
763     continue;
764     }
765 kumaneko 581 while (offset < PAGE_SIZE) {
766 kumaneko 3128 const unsigned char c = env_page.data[offset++];
767 kumaneko 2932 if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
768 kumaneko 581 if (c == '=') {
769     arg_ptr[arg_len++] = '\0';
770     } else if (c == '\\') {
771     arg_ptr[arg_len++] = '\\';
772     arg_ptr[arg_len++] = '\\';
773     } else if (c > ' ' && c < 127) {
774     arg_ptr[arg_len++] = c;
775     } else {
776     arg_ptr[arg_len++] = '\\';
777     arg_ptr[arg_len++] = (c >> 6) + '0';
778 kumaneko 1052 arg_ptr[arg_len++]
779     = ((c >> 3) & 7) + '0';
780 kumaneko 581 arg_ptr[arg_len++] = (c & 7) + '0';
781     }
782     } else {
783     arg_ptr[arg_len] = '\0';
784     }
785 kumaneko 1052 if (c)
786     continue;
787 kumaneko 2922 if (ccs_env_perm(r, arg_ptr)) {
788 kumaneko 581 error = -EPERM;
789     break;
790     }
791     if (!--envp_count) {
792     error = 0;
793     break;
794     }
795     arg_len = 0;
796     }
797     offset = 0;
798     }
799     out:
800 kumaneko 1657 if (r->mode != 3)
801 kumaneko 1052 error = 0;
802 kumaneko 3128 kfree(env_page.data);
803 kumaneko 3272 kfree(arg_ptr);
804 kumaneko 581 return error;
805     }
806 kumaneko 111
807 kumaneko 1052 /**
808 kumaneko 2002 * ccs_unescape - Unescape escaped string.
809 kumaneko 1052 *
810 kumaneko 2075 * @dest: String to unescape.
811 kumaneko 1052 *
812     * Returns nothing.
813     */
814 kumaneko 2002 static void ccs_unescape(unsigned char *dest)
815 kumaneko 708 {
816     unsigned char *src = dest;
817 kumaneko 1064 unsigned char c;
818     unsigned char d;
819     unsigned char e;
820 kumaneko 1747 while (1) {
821     c = *src++;
822     if (!c)
823     break;
824 kumaneko 708 if (c != '\\') {
825     *dest++ = c;
826     continue;
827     }
828     c = *src++;
829     if (c == '\\') {
830     *dest++ = c;
831 kumaneko 1052 continue;
832     }
833     if (c < '0' || c > '3')
834 kumaneko 708 break;
835 kumaneko 1052 d = *src++;
836     if (d < '0' || d > '7')
837     break;
838     e = *src++;
839     if (e < '0' || e > '7')
840     break;
841     *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
842 kumaneko 708 }
843     *dest = '\0';
844     }
845    
846 kumaneko 1052 /**
847 kumaneko 2002 * ccs_root_depth - Get number of directories to strip.
848 kumaneko 1052 *
849     * @dentry: Pointer to "struct dentry".
850     * @vfsmnt: Pointer to "struct vfsmount".
851     *
852     * Returns number of directories to strip.
853 kumaneko 1029 */
854 kumaneko 3625 static int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
855 kumaneko 708 {
856 kumaneko 1029 int depth = 0;
857 kumaneko 1474 ccs_realpath_lock();
858 kumaneko 1029 for (;;) {
859     if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
860     /* Global root? */
861 kumaneko 1052 if (vfsmnt->mnt_parent == vfsmnt)
862     break;
863 kumaneko 1029 dentry = vfsmnt->mnt_mountpoint;
864     vfsmnt = vfsmnt->mnt_parent;
865     continue;
866     }
867     dentry = dentry->d_parent;
868     depth++;
869     }
870 kumaneko 1474 ccs_realpath_unlock();
871 kumaneko 1052 return depth;
872     }
873    
874     /**
875 kumaneko 2002 * ccs_get_root_depth - return the depth of root directory.
876 kumaneko 1052 *
877     * Returns number of directories to strip.
878     */
879 kumaneko 2002 static int ccs_get_root_depth(void)
880 kumaneko 1052 {
881     int depth;
882     struct dentry *dentry;
883     struct vfsmount *vfsmnt;
884     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
885     struct path root;
886     #endif
887     read_lock(&current->fs->lock);
888     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
889     root = current->fs->root;
890     path_get(&current->fs->root);
891     dentry = root.dentry;
892     vfsmnt = root.mnt;
893     #else
894     dentry = dget(current->fs->root);
895     vfsmnt = mntget(current->fs->rootmnt);
896     #endif
897     read_unlock(&current->fs->lock);
898 kumaneko 2002 depth = ccs_root_depth(dentry, vfsmnt);
899 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
900 kumaneko 1029 path_put(&root);
901     #else
902 kumaneko 1052 dput(dentry);
903     mntput(vfsmnt);
904 kumaneko 1029 #endif
905     return depth;
906     }
907    
908 kumaneko 1052 /**
909 kumaneko 2002 * ccs_try_alt_exec - Try to start execute handler.
910 kumaneko 1052 *
911 kumaneko 3693 * @ee: Pointer to "struct ccs_execve".
912 kumaneko 1052 *
913     * Returns 0 on success, negative value otherwise.
914     */
915 kumaneko 3693 static int ccs_try_alt_exec(struct ccs_execve *ee)
916 kumaneko 1029 {
917 kumaneko 1005 /*
918     * Contents of modified bprm.
919     * The envp[] in original bprm is moved to argv[] so that
920     * the alternatively executed program won't be affected by
921 kumaneko 1064 * some dangerous environment variables like LD_PRELOAD.
922 kumaneko 1005 *
923     * modified bprm->argc
924     * = original bprm->argc + original bprm->envc + 7
925     * modified bprm->envc
926     * = 0
927     *
928     * modified bprm->argv[0]
929 kumaneko 1029 * = the program's name specified by execute_handler
930 kumaneko 1005 * modified bprm->argv[1]
931 kumaneko 2282 * = ccs_current_domain()->domainname->name
932 kumaneko 1005 * modified bprm->argv[2]
933     * = the current process's name
934     * modified bprm->argv[3]
935     * = the current process's information (e.g. uid/gid).
936     * modified bprm->argv[4]
937     * = original bprm->filename
938     * modified bprm->argv[5]
939     * = original bprm->argc in string expression
940     * modified bprm->argv[6]
941     * = original bprm->envc in string expression
942     * modified bprm->argv[7]
943     * = original bprm->argv[0]
944     * ...
945     * modified bprm->argv[bprm->argc + 6]
946     * = original bprm->argv[bprm->argc - 1]
947     * modified bprm->argv[bprm->argc + 7]
948     * = original bprm->envp[0]
949     * ...
950     * modified bprm->argv[bprm->envc + bprm->argc + 6]
951     * = original bprm->envp[bprm->envc - 1]
952     */
953 kumaneko 2037 struct linux_binprm *bprm = ee->bprm;
954 kumaneko 708 struct file *filp;
955     int retval;
956 kumaneko 1005 const int original_argc = bprm->argc;
957     const int original_envc = bprm->envc;
958     struct task_struct *task = current;
959 kumaneko 1032
960 kumaneko 1029 /* Close the requested program's dentry. */
961 kumaneko 3064 ee->obj.path1.dentry = NULL;
962     ee->obj.path1.mnt = NULL;
963     ee->obj.validate_done = false;
964 kumaneko 708 allow_write_access(bprm->file);
965     fput(bprm->file);
966     bprm->file = NULL;
967 kumaneko 1005
968 kumaneko 2037 /* Invalidate page dump cache. */
969     ee->dump.page = NULL;
970 kumaneko 1029
971 kumaneko 1005 /* Move envp[] to argv[] */
972     bprm->argc += bprm->envc;
973     bprm->envc = 0;
974    
975     /* Set argv[6] */
976     {
977 kumaneko 2037 char *cp = ee->tmp;
978     snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
979     retval = copy_strings_kernel(1, &cp, bprm);
980 kumaneko 1052 if (retval < 0)
981     goto out;
982 kumaneko 1005 bprm->argc++;
983     }
984    
985     /* Set argv[5] */
986     {
987 kumaneko 2037 char *cp = ee->tmp;
988     snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
989     retval = copy_strings_kernel(1, &cp, bprm);
990 kumaneko 1052 if (retval < 0)
991     goto out;
992 kumaneko 1005 bprm->argc++;
993     }
994    
995     /* Set argv[4] */
996     {
997 kumaneko 2075 retval = copy_strings_kernel(1, &bprm->filename, bprm);
998 kumaneko 1052 if (retval < 0)
999     goto out;
1000 kumaneko 1005 bprm->argc++;
1001     }
1002    
1003     /* Set argv[3] */
1004     {
1005 kumaneko 2037 char *cp = ee->tmp;
1006 kumaneko 2282 const u32 ccs_flags = task->ccs_flags;
1007 kumaneko 2037 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1008 kumaneko 1052 "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1009     "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1010     "state[1]=%u state[2]=%u",
1011 kumaneko 3502 (pid_t) ccsecurity_exports.sys_getpid(),
1012     current_uid(), current_gid(), current_euid(),
1013     current_egid(), current_suid(), current_sgid(),
1014     current_fsuid(), current_fsgid(),
1015 kumaneko 2282 (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
1016     (u8) (ccs_flags >> 8));
1017 kumaneko 2037 retval = copy_strings_kernel(1, &cp, bprm);
1018 kumaneko 1052 if (retval < 0)
1019     goto out;
1020 kumaneko 1005 bprm->argc++;
1021     }
1022    
1023     /* Set argv[2] */
1024     {
1025 kumaneko 1052 char *exe = (char *) ccs_get_exe();
1026 kumaneko 1005 if (exe) {
1027     retval = copy_strings_kernel(1, &exe, bprm);
1028 kumaneko 2711 kfree(exe);
1029 kumaneko 1005 } else {
1030 kumaneko 2037 exe = ee->tmp;
1031 kumaneko 2932 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
1032 kumaneko 2037 retval = copy_strings_kernel(1, &exe, bprm);
1033 kumaneko 1005 }
1034 kumaneko 1052 if (retval < 0)
1035     goto out;
1036 kumaneko 1005 bprm->argc++;
1037     }
1038    
1039     /* Set argv[1] */
1040     {
1041 kumaneko 2037 char *cp = ee->tmp;
1042 kumaneko 2932 snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
1043     ccs_current_domain()->domainname->name);
1044 kumaneko 2037 retval = copy_strings_kernel(1, &cp, bprm);
1045 kumaneko 1052 if (retval < 0)
1046     goto out;
1047 kumaneko 1005 bprm->argc++;
1048     }
1049    
1050     /* Set argv[0] */
1051     {
1052 kumaneko 2037 int depth = ccs_get_root_depth();
1053 kumaneko 2932 int len = ee->handler->total_len + 1;
1054 kumaneko 3512 char *cp = kmalloc(len, CCS_GFP_FLAGS);
1055 kumaneko 2932 if (!cp) {
1056 kumaneko 2998 retval = -ENOMEM;
1057 kumaneko 2932 goto out;
1058     }
1059     ee->handler_path = cp;
1060     memmove(cp, ee->handler->name, len);
1061 kumaneko 2037 ccs_unescape(cp);
1062     retval = -ENOENT;
1063     if (!*cp || *cp != '/')
1064     goto out;
1065     /* Adjust root directory for open_exec(). */
1066     while (depth) {
1067     cp = strchr(cp + 1, '/');
1068     if (!cp)
1069     goto out;
1070     depth--;
1071     }
1072 kumaneko 2932 memmove(ee->handler_path, cp, strlen(cp) + 1);
1073     cp = ee->handler_path;
1074 kumaneko 2037 retval = copy_strings_kernel(1, &cp, bprm);
1075 kumaneko 1052 if (retval < 0)
1076     goto out;
1077 kumaneko 1005 bprm->argc++;
1078     }
1079 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1080     #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1081 kumaneko 1007 bprm->argv_len = bprm->exec - bprm->p;
1082     #endif
1083 kumaneko 1052 #endif
1084 kumaneko 1005
1085 kumaneko 3625 /*
1086     * OK, now restart the process with execute handler program's dentry.
1087     */
1088 kumaneko 2932 filp = open_exec(ee->handler_path);
1089 kumaneko 1005 if (IS_ERR(filp)) {
1090     retval = PTR_ERR(filp);
1091     goto out;
1092     }
1093 kumaneko 3064 ee->obj.path1.dentry = filp->f_dentry;
1094     ee->obj.path1.mnt = filp->f_vfsmnt;
1095 kumaneko 1052 bprm->file = filp;
1096 kumaneko 2932 bprm->filename = ee->handler_path;
1097 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1098 kumaneko 2076 bprm->interp = bprm->filename;
1099 kumaneko 708 #endif
1100 kumaneko 1029 retval = prepare_binprm(bprm);
1101 kumaneko 1052 if (retval < 0)
1102     goto out;
1103 kumaneko 2932 task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1104     retval = ccs_find_next_domain(ee);
1105     task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1106 kumaneko 1005 out:
1107     return retval;
1108 kumaneko 708 }
1109 kumaneko 581
1110 kumaneko 1052 /**
1111 kumaneko 2002 * ccs_find_execute_handler - Find an execute handler.
1112 kumaneko 1052 *
1113 kumaneko 3693 * @ee: Pointer to "struct ccs_execve".
1114 kumaneko 1052 * @type: Type of execute handler.
1115     *
1116 kumaneko 2075 * Returns true if found, false otherwise.
1117 kumaneko 2690 *
1118 kumaneko 2828 * Caller holds ccs_read_lock().
1119 kumaneko 1052 */
1120 kumaneko 3697 static bool ccs_find_execute_handler(struct ccs_execve *ee, const u8 type)
1121 kumaneko 1029 {
1122 kumaneko 3741 struct ccs_request_info *r = &ee->r;
1123     const struct ccs_domain_info *domain = ccs_current_domain();
1124 kumaneko 2002 struct ccs_acl_info *ptr;
1125 kumaneko 1064 /*
1126     * Don't use execute handler if the current process is
1127     * marked as execute handler to avoid infinite execute handler loop.
1128     */
1129 kumaneko 3741 if (current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1130 kumaneko 2037 return false;
1131 kumaneko 3741 retry:
1132 kumaneko 3697 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1133     struct ccs_execute_handler *acl;
1134 kumaneko 3741 if (ptr->type != type || !ccs_condition(r, ptr->cond))
1135 kumaneko 1052 continue;
1136 kumaneko 3697 acl = container_of(ptr, struct ccs_execute_handler, head);
1137 kumaneko 2037 ee->handler = acl->handler;
1138 kumaneko 3627 ee->handler_type = type;
1139 kumaneko 3741 r->cond = ptr->cond;
1140     return true;
1141 kumaneko 1029 }
1142 kumaneko 3747 if (domain != &ccs_global_domain && !domain->flags[CCS_DIF_IGNORE_GLOBAL]) {
1143 kumaneko 3741 domain = &ccs_global_domain;
1144     goto retry;
1145     }
1146     return false;
1147 kumaneko 1029 }
1148    
1149 kumaneko 3741 #ifdef CONFIG_MMU
1150     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1151     #define CCS_BPRM_MMU
1152     #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3
1153     #define CCS_BPRM_MMU
1154     #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2
1155     #define CCS_BPRM_MMU
1156     #endif
1157     #endif
1158    
1159 kumaneko 1052 /**
1160 kumaneko 2037 * ccs_dump_page - Dump a page to buffer.
1161 kumaneko 1657 *
1162 kumaneko 2037 * @bprm: Pointer to "struct linux_binprm".
1163     * @pos: Location to dump.
1164     * @dump: Poiner to "struct ccs_page_dump".
1165 kumaneko 1657 *
1166 kumaneko 2037 * Returns true on success, false otherwise.
1167 kumaneko 1657 */
1168 kumaneko 2037 bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1169     struct ccs_page_dump *dump)
1170 kumaneko 1657 {
1171 kumaneko 2037 struct page *page;
1172 kumaneko 3056 /* dump->data is released by ccs_finish_execve(). */
1173 kumaneko 2037 if (!dump->data) {
1174 kumaneko 3512 dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1175 kumaneko 2037 if (!dump->data)
1176     return false;
1177     }
1178     /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1179 kumaneko 3741 #ifdef CCS_BPRM_MMU
1180 kumaneko 2037 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1181     return false;
1182     #else
1183     page = bprm->page[pos / PAGE_SIZE];
1184     #endif
1185     if (page != dump->page) {
1186     const unsigned int offset = pos % PAGE_SIZE;
1187     /*
1188     * Maybe kmap()/kunmap() should be used here.
1189     * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1190     * So do I.
1191     */
1192     char *kaddr = kmap_atomic(page, KM_USER0);
1193     dump->page = page;
1194 kumaneko 3625 memcpy(dump->data + offset, kaddr + offset,
1195     PAGE_SIZE - offset);
1196 kumaneko 2037 kunmap_atomic(kaddr, KM_USER0);
1197     }
1198     /* Same with put_arg_page(page) in fs/exec.c */
1199 kumaneko 3741 #ifdef CCS_BPRM_MMU
1200 kumaneko 2037 put_page(page);
1201     #endif
1202     return true;
1203 kumaneko 1657 }
1204    
1205     /**
1206 kumaneko 2037 * ccs_start_execve - Prepare for execve() operation.
1207 kumaneko 1052 *
1208     * @bprm: Pointer to "struct linux_binprm".
1209 kumaneko 3693 * @eep: Pointer to "struct ccs_execve *".
1210 kumaneko 1052 *
1211 kumaneko 2037 * Returns 0 on success, negative value otherwise.
1212 kumaneko 1052 */
1213 kumaneko 3502 static int ccs_start_execve(struct linux_binprm *bprm,
1214 kumaneko 3693 struct ccs_execve **eep)
1215 kumaneko 115 {
1216 kumaneko 1657 int retval;
1217 kumaneko 1029 struct task_struct *task = current;
1218 kumaneko 3693 struct ccs_execve *ee;
1219 kumaneko 3056 *eep = NULL;
1220 kumaneko 3512 ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1221 kumaneko 2037 if (!ee)
1222 kumaneko 1052 return -ENOMEM;
1223 kumaneko 3512 ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1224 kumaneko 3056 if (!ee->tmp) {
1225     kfree(ee);
1226     return -ENOMEM;
1227     }
1228     ee->reader_idx = ccs_read_lock();
1229     /* ee->dump->data is allocated by ccs_dump_page(). */
1230     ee->previous_domain = task->ccs_domain_info;
1231     /* Clear manager flag. */
1232 kumaneko 3693 task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
1233 kumaneko 3056 *eep = ee;
1234 kumaneko 3627 ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1235 kumaneko 2037 ee->r.ee = ee;
1236     ee->bprm = bprm;
1237     ee->r.obj = &ee->obj;
1238 kumaneko 2915 ee->obj.path1.dentry = bprm->file->f_dentry;
1239     ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1240 kumaneko 3627 /*
1241     * No need to call ccs_environ() for execute handler because envp[] is
1242     * moved to argv[].
1243     */
1244     if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER))
1245     return ccs_try_alt_exec(ee);
1246 kumaneko 2037 retval = ccs_find_next_domain(ee);
1247 kumaneko 3627 if (retval == -EPERM) {
1248     if (ccs_find_execute_handler(ee,
1249     CCS_TYPE_DENIED_EXECUTE_HANDLER))
1250     return ccs_try_alt_exec(ee);
1251 kumaneko 1052 }
1252 kumaneko 3627 if (!retval)
1253     retval = ccs_environ(ee);
1254 kumaneko 2037 return retval;
1255     }
1256    
1257     /**
1258     * ccs_finish_execve - Clean up execve() operation.
1259 kumaneko 2076 *
1260     * @retval: Return code of an execve() operation.
1261 kumaneko 3693 * @ee: Pointer to "struct ccs_execve".
1262 kumaneko 2690 *
1263 kumaneko 2828 * Caller holds ccs_read_lock().
1264 kumaneko 2037 */
1265 kumaneko 3693 static void ccs_finish_execve(int retval, struct ccs_execve *ee)
1266 kumaneko 2037 {
1267     struct task_struct *task = current;
1268     if (!ee)
1269     return;
1270 kumaneko 2968 if (retval < 0) {
1271     task->ccs_domain_info = ee->previous_domain;
1272 kumaneko 3056 /*
1273     * Make task->ccs_domain_info visible to GC before changing
1274     * task->ccs_flags .
1275     */
1276     smp_mb();
1277     } else {
1278     /* Mark the current process as execute handler. */
1279     if (ee->handler)
1280     task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1281     /* Mark the current process as normal process. */
1282     else
1283     task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1284 kumaneko 2968 }
1285 kumaneko 3056 /* Tell GC that I finished execve(). */
1286     task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1287     ccs_read_unlock(ee->reader_idx);
1288     kfree(ee->handler_path);
1289     kfree(ee->tmp);
1290     kfree(ee->dump.data);
1291     kfree(ee);
1292 kumaneko 115 }
1293 kumaneko 3484
1294     /**
1295     * ccs_may_transit - Check permission and do domain transition without execve().
1296     *
1297     * @domainname: Domainname to transit to.
1298     * @pathname: Pathname to check.
1299     *
1300     * Returns 0 on success, negative value otherwise.
1301     *
1302     * Caller holds ccs_read_lock().
1303     */
1304 kumaneko 3512 int ccs_may_transit(const char *domainname, const char *pathname)
1305     {
1306 kumaneko 3484 struct ccs_path_info name;
1307     struct ccs_request_info r;
1308     struct ccs_domain_info *domain;
1309     int error;
1310 kumaneko 3627 bool domain_created = false;
1311 kumaneko 3484 name.name = pathname;
1312     ccs_fill_path_info(&name);
1313     /* Check allow_transit permission. */
1314 kumaneko 3627 ccs_init_request_info(&r, CCS_MAC_FILE_TRANSIT);
1315 kumaneko 3484 error = ccs_path_permission(&r, CCS_TYPE_TRANSIT, &name);
1316     if (error)
1317     return error;
1318     /* Check destination domain. */
1319     domain = ccs_find_domain(domainname);
1320     if (!domain && r.mode != CCS_CONFIG_ENFORCING &&
1321     strlen(domainname) < CCS_EXEC_TMPSIZE - 10) {
1322 kumaneko 3694 domain = ccs_assign_domain(domainname, r.profile);
1323 kumaneko 3484 if (domain)
1324 kumaneko 3627 domain_created = true;
1325 kumaneko 3484 }
1326     if (domain) {
1327     error = 0;
1328     current->ccs_domain_info = domain;
1329 kumaneko 3627 if (domain_created)
1330     ccs_audit_domain_creation_log();
1331 kumaneko 3484 } else {
1332     error = -ENOENT;
1333     }
1334     return error;
1335     }
1336 kumaneko 3502
1337     static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1338     struct pt_regs *regs)
1339     {
1340 kumaneko 3693 struct ccs_execve *ee;
1341 kumaneko 3502 int retval;
1342     if (!ccs_policy_loaded)
1343     ccsecurity_exports.load_policy(bprm->filename);
1344     retval = ccs_start_execve(bprm, &ee);
1345     if (!retval)
1346     retval = search_binary_handler(bprm, regs);
1347     ccs_finish_execve(retval, ee);
1348     return retval;
1349     }
1350    
1351     void __init ccs_domain_init(void)
1352     {
1353     ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1354     }

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