aboutsummaryrefslogtreecommitdiffstats
path: root/security/tomoyo/domain.c
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2011-06-26 10:19:52 -0400
committerJames Morris <jmorris@namei.org>2011-06-28 19:31:21 -0400
commitbd03a3e4c9a9df0c6b007045fa7fc8889111a478 (patch)
tree9d78290c878e6466fe3e0bda7ee5989c0dc39e40 /security/tomoyo/domain.c
parent32997144fd9925fc4d506a16990a0c405f766526 (diff)
TOMOYO: Add policy namespace support.
Mauras Olivier reported that it is difficult to use TOMOYO in LXC environments, for TOMOYO cannot distinguish between environments outside the container and environments inside the container since LXC environments are created using pivot_root(). To address this problem, this patch introduces policy namespace. Each policy namespace has its own set of domain policy, exception policy and profiles, which are all independent of other namespaces. This independency allows users to develop policy without worrying interference among namespaces. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/domain.c')
-rw-r--r--security/tomoyo/domain.c360
1 files changed, 260 insertions, 100 deletions
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index af5f325e2f33..71acebc747c3 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -12,9 +12,6 @@
12 12
13/* Variables definitions.*/ 13/* Variables definitions.*/
14 14
15/* The global ACL referred by "use_group" keyword. */
16struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS];
17
18/* The initial domain. */ 15/* The initial domain. */
19struct tomoyo_domain_info tomoyo_kernel_domain; 16struct tomoyo_domain_info tomoyo_kernel_domain;
20 17
@@ -158,7 +155,7 @@ retry:
158 } 155 }
159 if (!retried) { 156 if (!retried) {
160 retried = true; 157 retried = true;
161 list = &tomoyo_acl_group[domain->group]; 158 list = &domain->ns->acl_group[domain->group];
162 goto retry; 159 goto retry;
163 } 160 }
164 r->granted = false; 161 r->granted = false;
@@ -167,13 +164,10 @@ retry:
167/* The list for "struct tomoyo_domain_info". */ 164/* The list for "struct tomoyo_domain_info". */
168LIST_HEAD(tomoyo_domain_list); 165LIST_HEAD(tomoyo_domain_list);
169 166
170struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
171struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
172
173/** 167/**
174 * tomoyo_last_word - Get last component of a domainname. 168 * tomoyo_last_word - Get last component of a domainname.
175 * 169 *
176 * @domainname: Domainname to check. 170 * @name: Domainname to check.
177 * 171 *
178 * Returns the last word of @domainname. 172 * Returns the last word of @domainname.
179 */ 173 */
@@ -247,7 +241,7 @@ int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
247 if (!e.domainname) 241 if (!e.domainname)
248 goto out; 242 goto out;
249 } 243 }
250 param->list = &tomoyo_policy_list[TOMOYO_ID_TRANSITION_CONTROL]; 244 param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
251 error = tomoyo_update_policy(&e.head, sizeof(e), param, 245 error = tomoyo_update_policy(&e.head, sizeof(e), param,
252 tomoyo_same_transition_control); 246 tomoyo_same_transition_control);
253out: 247out:
@@ -257,59 +251,88 @@ out:
257} 251}
258 252
259/** 253/**
260 * tomoyo_transition_type - Get domain transition type. 254 * tomoyo_scan_transition - Try to find specific domain transition type.
261 * 255 *
262 * @domainname: The name of domain. 256 * @list: Pointer to "struct list_head".
263 * @program: The name of program. 257 * @domainname: The name of current domain.
258 * @program: The name of requested program.
259 * @last_name: The last component of @domainname.
260 * @type: One of values in "enum tomoyo_transition_type".
264 * 261 *
265 * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program 262 * Returns true if found one, false otherwise.
266 * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
267 * @program suppresses domain transition, others otherwise.
268 * 263 *
269 * Caller holds tomoyo_read_lock(). 264 * Caller holds tomoyo_read_lock().
270 */ 265 */
271static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, 266static inline bool tomoyo_scan_transition
272 const struct tomoyo_path_info *program) 267(const struct list_head *list, const struct tomoyo_path_info *domainname,
268 const struct tomoyo_path_info *program, const char *last_name,
269 const enum tomoyo_transition_type type)
273{ 270{
274 const struct tomoyo_transition_control *ptr; 271 const struct tomoyo_transition_control *ptr;
275 const char *last_name = tomoyo_last_word(domainname->name); 272 list_for_each_entry_rcu(ptr, list, head.list) {
276 u8 type; 273 if (ptr->head.is_deleted || ptr->type != type)
277 for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) { 274 continue;
278 next: 275 if (ptr->domainname) {
279 list_for_each_entry_rcu(ptr, &tomoyo_policy_list 276 if (!ptr->is_last_name) {
280 [TOMOYO_ID_TRANSITION_CONTROL], 277 if (ptr->domainname != domainname)
281 head.list) { 278 continue;
282 if (ptr->head.is_deleted || ptr->type != type) 279 } else {
283 continue;
284 if (ptr->domainname) {
285 if (!ptr->is_last_name) {
286 if (ptr->domainname != domainname)
287 continue;
288 } else {
289 /*
290 * Use direct strcmp() since this is
291 * unlikely used.
292 */
293 if (strcmp(ptr->domainname->name,
294 last_name))
295 continue;
296 }
297 }
298 if (ptr->program &&
299 tomoyo_pathcmp(ptr->program, program))
300 continue;
301 if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) {
302 /* 280 /*
303 * Do not check for initialize_domain if 281 * Use direct strcmp() since this is
304 * no_initialize_domain matched. 282 * unlikely used.
305 */ 283 */
306 type = TOMOYO_TRANSITION_CONTROL_NO_KEEP; 284 if (strcmp(ptr->domainname->name, last_name))
307 goto next; 285 continue;
308 } 286 }
309 goto done;
310 } 287 }
288 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
289 continue;
290 return true;
291 }
292 return false;
293}
294
295/**
296 * tomoyo_transition_type - Get domain transition type.
297 *
298 * @ns: Pointer to "struct tomoyo_policy_namespace".
299 * @domainname: The name of current domain.
300 * @program: The name of requested program.
301 *
302 * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes
303 * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if
304 * executing @program reinitializes domain transition within that namespace,
305 * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
306 * others otherwise.
307 *
308 * Caller holds tomoyo_read_lock().
309 */
310static enum tomoyo_transition_type tomoyo_transition_type
311(const struct tomoyo_policy_namespace *ns,
312 const struct tomoyo_path_info *domainname,
313 const struct tomoyo_path_info *program)
314{
315 const char *last_name = tomoyo_last_word(domainname->name);
316 enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
317 while (type < TOMOYO_MAX_TRANSITION_TYPE) {
318 const struct list_head * const list =
319 &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
320 if (!tomoyo_scan_transition(list, domainname, program,
321 last_name, type)) {
322 type++;
323 continue;
324 }
325 if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET &&
326 type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE)
327 break;
328 /*
329 * Do not check for reset_domain if no_reset_domain matched.
330 * Do not check for initialize_domain if no_initialize_domain
331 * matched.
332 */
333 type++;
334 type++;
311 } 335 }
312 done:
313 return type; 336 return type;
314} 337}
315 338
@@ -355,7 +378,7 @@ int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
355 if (!e.original_name || !e.aggregated_name || 378 if (!e.original_name || !e.aggregated_name ||
356 e.aggregated_name->is_patterned) /* No patterns allowed. */ 379 e.aggregated_name->is_patterned) /* No patterns allowed. */
357 goto out; 380 goto out;
358 param->list = &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR]; 381 param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
359 error = tomoyo_update_policy(&e.head, sizeof(e), param, 382 error = tomoyo_update_policy(&e.head, sizeof(e), param,
360 tomoyo_same_aggregator); 383 tomoyo_same_aggregator);
361out: 384out:
@@ -365,53 +388,171 @@ out:
365} 388}
366 389
367/** 390/**
368 * tomoyo_assign_domain - Create a domain. 391 * tomoyo_find_namespace - Find specified namespace.
369 * 392 *
370 * @domainname: The name of domain. 393 * @name: Name of namespace to find.
371 * @profile: Profile number to assign if the domain was newly created. 394 * @len: Length of @name.
372 * 395 *
373 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. 396 * Returns pointer to "struct tomoyo_policy_namespace" if found,
397 * NULL otherwise.
374 * 398 *
375 * Caller holds tomoyo_read_lock(). 399 * Caller holds tomoyo_read_lock().
376 */ 400 */
377struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, 401static struct tomoyo_policy_namespace *tomoyo_find_namespace
378 const u8 profile) 402(const char *name, const unsigned int len)
379{ 403{
380 struct tomoyo_domain_info *entry; 404 struct tomoyo_policy_namespace *ns;
381 struct tomoyo_domain_info *domain = NULL; 405 list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
382 const struct tomoyo_path_info *saved_domainname; 406 if (strncmp(name, ns->name, len) ||
383 bool found = false; 407 (name[len] && name[len] != ' '))
408 continue;
409 return ns;
410 }
411 return NULL;
412}
384 413
385 if (!tomoyo_correct_domain(domainname)) 414/**
415 * tomoyo_assign_namespace - Create a new namespace.
416 *
417 * @domainname: Name of namespace to create.
418 *
419 * Returns pointer to "struct tomoyo_policy_namespace" on success,
420 * NULL otherwise.
421 *
422 * Caller holds tomoyo_read_lock().
423 */
424struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
425{
426 struct tomoyo_policy_namespace *ptr;
427 struct tomoyo_policy_namespace *entry;
428 const char *cp = domainname;
429 unsigned int len = 0;
430 while (*cp && *cp++ != ' ')
431 len++;
432 ptr = tomoyo_find_namespace(domainname, len);
433 if (ptr)
434 return ptr;
435 if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname))
386 return NULL; 436 return NULL;
387 saved_domainname = tomoyo_get_name(domainname); 437 entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
388 if (!saved_domainname) 438 if (!entry)
389 return NULL; 439 return NULL;
390 entry = kzalloc(sizeof(*entry), GFP_NOFS);
391 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 440 if (mutex_lock_interruptible(&tomoyo_policy_lock))
392 goto out; 441 goto out;
393 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 442 ptr = tomoyo_find_namespace(domainname, len);
394 if (domain->is_deleted || 443 if (!ptr && tomoyo_memory_ok(entry)) {
395 tomoyo_pathcmp(saved_domainname, domain->domainname)) 444 char *name = (char *) (entry + 1);
396 continue; 445 ptr = entry;
397 found = true; 446 memmove(name, domainname, len);
398 break; 447 name[len] = '\0';
399 } 448 entry->name = name;
400 if (!found && tomoyo_memory_ok(entry)) { 449 tomoyo_init_policy_namespace(entry);
401 INIT_LIST_HEAD(&entry->acl_info_list);
402 entry->domainname = saved_domainname;
403 saved_domainname = NULL;
404 entry->profile = profile;
405 list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
406 domain = entry;
407 entry = NULL; 450 entry = NULL;
408 found = true;
409 } 451 }
410 mutex_unlock(&tomoyo_policy_lock); 452 mutex_unlock(&tomoyo_policy_lock);
411 out: 453out:
412 tomoyo_put_name(saved_domainname);
413 kfree(entry); 454 kfree(entry);
414 return found ? domain : NULL; 455 return ptr;
456}
457
458/**
459 * tomoyo_namespace_jump - Check for namespace jump.
460 *
461 * @domainname: Name of domain.
462 *
463 * Returns true if namespace differs, false otherwise.
464 */
465static bool tomoyo_namespace_jump(const char *domainname)
466{
467 const char *namespace = tomoyo_current_namespace()->name;
468 const int len = strlen(namespace);
469 return strncmp(domainname, namespace, len) ||
470 (domainname[len] && domainname[len] != ' ');
471}
472
473/**
474 * tomoyo_assign_domain - Create a domain or a namespace.
475 *
476 * @domainname: The name of domain.
477 * @transit: True if transit to domain found or created.
478 *
479 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
480 *
481 * Caller holds tomoyo_read_lock().
482 */
483struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
484 const bool transit)
485{
486 struct tomoyo_domain_info e = { };
487 struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
488 bool created = false;
489 if (entry) {
490 if (transit) {
491 /*
492 * Since namespace is created at runtime, profiles may
493 * not be created by the moment the process transits to
494 * that domain. Do not perform domain transition if
495 * profile for that domain is not yet created.
496 */
497 if (!entry->ns->profile_ptr[entry->profile])
498 return NULL;
499 }
500 return entry;
501 }
502 /* Requested domain does not exist. */
503 /* Don't create requested domain if domainname is invalid. */
504 if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
505 !tomoyo_correct_domain(domainname))
506 return NULL;
507 /*
508 * Since definition of profiles and acl_groups may differ across
509 * namespaces, do not inherit "use_profile" and "use_group" settings
510 * by automatically creating requested domain upon domain transition.
511 */
512 if (transit && tomoyo_namespace_jump(domainname))
513 return NULL;
514 e.ns = tomoyo_assign_namespace(domainname);
515 if (!e.ns)
516 return NULL;
517 /*
518 * "use_profile" and "use_group" settings for automatically created
519 * domains are inherited from current domain. These are 0 for manually
520 * created domains.
521 */
522 if (transit) {
523 const struct tomoyo_domain_info *domain = tomoyo_domain();
524 e.profile = domain->profile;
525 e.group = domain->group;
526 }
527 e.domainname = tomoyo_get_name(domainname);
528 if (!e.domainname)
529 return NULL;
530 if (mutex_lock_interruptible(&tomoyo_policy_lock))
531 goto out;
532 entry = tomoyo_find_domain(domainname);
533 if (!entry) {
534 entry = tomoyo_commit_ok(&e, sizeof(e));
535 if (entry) {
536 INIT_LIST_HEAD(&entry->acl_info_list);
537 list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
538 created = true;
539 }
540 }
541 mutex_unlock(&tomoyo_policy_lock);
542out:
543 tomoyo_put_name(e.domainname);
544 if (entry && transit) {
545 if (created) {
546 struct tomoyo_request_info r;
547 tomoyo_init_request_info(&r, entry,
548 TOMOYO_MAC_FILE_EXECUTE);
549 r.granted = false;
550 tomoyo_write_log(&r, "use_profile %u\n",
551 entry->profile);
552 tomoyo_write_log(&r, "use_group %u\n", entry->group);
553 }
554 }
555 return entry;
415} 556}
416 557
417/** 558/**
@@ -434,6 +575,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
434 bool is_enforce; 575 bool is_enforce;
435 int retval = -ENOMEM; 576 int retval = -ENOMEM;
436 bool need_kfree = false; 577 bool need_kfree = false;
578 bool reject_on_transition_failure = false;
437 struct tomoyo_path_info rn = { }; /* real name */ 579 struct tomoyo_path_info rn = { }; /* real name */
438 580
439 mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); 581 mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
@@ -457,8 +599,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
457 /* Check 'aggregator' directive. */ 599 /* Check 'aggregator' directive. */
458 { 600 {
459 struct tomoyo_aggregator *ptr; 601 struct tomoyo_aggregator *ptr;
460 list_for_each_entry_rcu(ptr, &tomoyo_policy_list 602 struct list_head *list =
461 [TOMOYO_ID_AGGREGATOR], head.list) { 603 &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
604 /* Check 'aggregator' directive. */
605 list_for_each_entry_rcu(ptr, list, head.list) {
462 if (ptr->head.is_deleted || 606 if (ptr->head.is_deleted ||
463 !tomoyo_path_matches_pattern(&rn, 607 !tomoyo_path_matches_pattern(&rn,
464 ptr->original_name)) 608 ptr->original_name))
@@ -492,11 +636,21 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
492 } 636 }
493 637
494 /* Calculate domain to transit to. */ 638 /* Calculate domain to transit to. */
495 switch (tomoyo_transition_type(old_domain->domainname, &rn)) { 639 switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
640 &rn)) {
641 case TOMOYO_TRANSITION_CONTROL_RESET:
642 /* Transit to the root of specified namespace. */
643 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
644 /*
645 * Make do_execve() fail if domain transition across namespaces
646 * has failed.
647 */
648 reject_on_transition_failure = true;
649 break;
496 case TOMOYO_TRANSITION_CONTROL_INITIALIZE: 650 case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
497 /* Transit to the child of tomoyo_kernel_domain domain. */ 651 /* Transit to the child of current namespace's root. */
498 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " " 652 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
499 "%s", rn.name); 653 old_domain->ns->name, rn.name);
500 break; 654 break;
501 case TOMOYO_TRANSITION_CONTROL_KEEP: 655 case TOMOYO_TRANSITION_CONTROL_KEEP:
502 /* Keep current domain. */ 656 /* Keep current domain. */
@@ -519,19 +673,25 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
519 } 673 }
520 break; 674 break;
521 } 675 }
522 if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
523 goto done;
524 domain = tomoyo_find_domain(tmp);
525 if (!domain) 676 if (!domain)
526 domain = tomoyo_assign_domain(tmp, old_domain->profile); 677 domain = tomoyo_assign_domain(tmp, true);
527 done:
528 if (domain) 678 if (domain)
529 goto out; 679 retval = 0;
530 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp); 680 else if (reject_on_transition_failure) {
531 if (is_enforce) 681 printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", tmp);
532 retval = -EPERM; 682 retval = -ENOMEM;
533 else 683 } else if (r.mode == TOMOYO_CONFIG_ENFORCING)
534 old_domain->transition_failed = true; 684 retval = -ENOMEM;
685 else {
686 retval = 0;
687 if (!old_domain->transition_failed) {
688 old_domain->transition_failed = true;
689 r.granted = false;
690 tomoyo_write_log(&r, "%s", "transition_failed\n");
691 printk(KERN_WARNING
692 "ERROR: Domain '%s' not defined.\n", tmp);
693 }
694 }
535 out: 695 out:
536 if (!domain) 696 if (!domain)
537 domain = old_domain; 697 domain = old_domain;