Commit bd03a3e4 authored by Tetsuo Handa's avatar Tetsuo Handa Committed by James Morris

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: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 32997144
...@@ -151,13 +151,15 @@ static unsigned int tomoyo_log_count; ...@@ -151,13 +151,15 @@ static unsigned int tomoyo_log_count;
/** /**
* tomoyo_get_audit - Get audit mode. * tomoyo_get_audit - Get audit mode.
* *
* @ns: Pointer to "struct tomoyo_policy_namespace".
* @profile: Profile number. * @profile: Profile number.
* @index: Index number of functionality. * @index: Index number of functionality.
* @is_granted: True if granted log, false otherwise. * @is_granted: True if granted log, false otherwise.
* *
* Returns true if this request should be audited, false otherwise. * Returns true if this request should be audited, false otherwise.
*/ */
static bool tomoyo_get_audit(const u8 profile, const u8 index, static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
const u8 profile, const u8 index,
const bool is_granted) const bool is_granted)
{ {
u8 mode; u8 mode;
...@@ -165,7 +167,7 @@ static bool tomoyo_get_audit(const u8 profile, const u8 index, ...@@ -165,7 +167,7 @@ static bool tomoyo_get_audit(const u8 profile, const u8 index,
struct tomoyo_profile *p; struct tomoyo_profile *p;
if (!tomoyo_policy_loaded) if (!tomoyo_policy_loaded)
return false; return false;
p = tomoyo_profile(profile); p = tomoyo_profile(ns, profile);
if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
return false; return false;
mode = p->config[index]; mode = p->config[index];
...@@ -194,7 +196,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, ...@@ -194,7 +196,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
char *buf; char *buf;
struct tomoyo_log *entry; struct tomoyo_log *entry;
bool quota_exceeded = false; bool quota_exceeded = false;
if (!tomoyo_get_audit(r->profile, r->type, r->granted)) if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted))
goto out; goto out;
buf = tomoyo_init_log(r, len, fmt, args); buf = tomoyo_init_log(r, len, fmt, args);
if (!buf) if (!buf)
......
...@@ -11,12 +11,6 @@ ...@@ -11,12 +11,6 @@
#include <linux/security.h> #include <linux/security.h>
#include "common.h" #include "common.h"
/* Profile version. Currently only 20090903 is defined. */
static unsigned int tomoyo_profile_version;
/* Profile table. Memory is allocated as needed. */
static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
/* String table for operation mode. */ /* String table for operation mode. */
const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = {
[TOMOYO_CONFIG_DISABLED] = "disabled", [TOMOYO_CONFIG_DISABLED] = "disabled",
...@@ -216,6 +210,50 @@ static void tomoyo_set_slash(struct tomoyo_io_buffer *head) ...@@ -216,6 +210,50 @@ static void tomoyo_set_slash(struct tomoyo_io_buffer *head)
tomoyo_set_string(head, "/"); tomoyo_set_string(head, "/");
} }
/* List of namespaces. */
LIST_HEAD(tomoyo_namespace_list);
/* True if namespace other than tomoyo_kernel_namespace is defined. */
static bool tomoyo_namespace_enabled;
/**
* tomoyo_init_policy_namespace - Initialize namespace.
*
* @ns: Pointer to "struct tomoyo_policy_namespace".
*
* Returns nothing.
*/
void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
{
unsigned int idx;
for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
INIT_LIST_HEAD(&ns->acl_group[idx]);
for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
INIT_LIST_HEAD(&ns->group_list[idx]);
for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
INIT_LIST_HEAD(&ns->policy_list[idx]);
ns->profile_version = 20100903;
tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
}
/**
* tomoyo_print_namespace - Print namespace header.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
* Returns nothing.
*/
static void tomoyo_print_namespace(struct tomoyo_io_buffer *head)
{
if (!tomoyo_namespace_enabled)
return;
tomoyo_set_string(head,
container_of(head->r.ns,
struct tomoyo_policy_namespace,
namespace_list)->name);
tomoyo_set_space(head);
}
/** /**
* tomoyo_print_name_union - Print a tomoyo_name_union. * tomoyo_print_name_union - Print a tomoyo_name_union.
* *
...@@ -283,23 +321,25 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, ...@@ -283,23 +321,25 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
/** /**
* tomoyo_assign_profile - Create a new profile. * tomoyo_assign_profile - Create a new profile.
* *
* @ns: Pointer to "struct tomoyo_policy_namespace".
* @profile: Profile number to create. * @profile: Profile number to create.
* *
* Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
*/ */
static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) static struct tomoyo_profile *tomoyo_assign_profile
(struct tomoyo_policy_namespace *ns, const unsigned int profile)
{ {
struct tomoyo_profile *ptr; struct tomoyo_profile *ptr;
struct tomoyo_profile *entry; struct tomoyo_profile *entry;
if (profile >= TOMOYO_MAX_PROFILES) if (profile >= TOMOYO_MAX_PROFILES)
return NULL; return NULL;
ptr = tomoyo_profile_ptr[profile]; ptr = ns->profile_ptr[profile];
if (ptr) if (ptr)
return ptr; return ptr;
entry = kzalloc(sizeof(*entry), GFP_NOFS); entry = kzalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
ptr = tomoyo_profile_ptr[profile]; ptr = ns->profile_ptr[profile];
if (!ptr && tomoyo_memory_ok(entry)) { if (!ptr && tomoyo_memory_ok(entry)) {
ptr = entry; ptr = entry;
ptr->default_config = TOMOYO_CONFIG_DISABLED | ptr->default_config = TOMOYO_CONFIG_DISABLED |
...@@ -310,7 +350,7 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) ...@@ -310,7 +350,7 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile)
ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024; ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024;
ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048;
mb(); /* Avoid out-of-order execution. */ mb(); /* Avoid out-of-order execution. */
tomoyo_profile_ptr[profile] = ptr; ns->profile_ptr[profile] = ptr;
entry = NULL; entry = NULL;
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
...@@ -322,14 +362,16 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) ...@@ -322,14 +362,16 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile)
/** /**
* tomoyo_profile - Find a profile. * tomoyo_profile - Find a profile.
* *
* @ns: Pointer to "struct tomoyo_policy_namespace".
* @profile: Profile number to find. * @profile: Profile number to find.
* *
* Returns pointer to "struct tomoyo_profile". * Returns pointer to "struct tomoyo_profile".
*/ */
struct tomoyo_profile *tomoyo_profile(const u8 profile) struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
const u8 profile)
{ {
static struct tomoyo_profile tomoyo_null_profile; static struct tomoyo_profile tomoyo_null_profile;
struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile]; struct tomoyo_profile *ptr = ns->profile_ptr[profile];
if (!ptr) if (!ptr)
ptr = &tomoyo_null_profile; ptr = &tomoyo_null_profile;
return ptr; return ptr;
...@@ -454,13 +496,14 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) ...@@ -454,13 +496,14 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
unsigned int i; unsigned int i;
char *cp; char *cp;
struct tomoyo_profile *profile; struct tomoyo_profile *profile;
if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1) if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
== 1)
return 0; return 0;
i = simple_strtoul(data, &cp, 10); i = simple_strtoul(data, &cp, 10);
if (*cp != '-') if (*cp != '-')
return -EINVAL; return -EINVAL;
data = cp + 1; data = cp + 1;
profile = tomoyo_assign_profile(i); profile = tomoyo_assign_profile(head->w.ns, i);
if (!profile) if (!profile)
return -EINVAL; return -EINVAL;
cp = strchr(data, '='); cp = strchr(data, '=');
...@@ -518,19 +561,25 @@ static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) ...@@ -518,19 +561,25 @@ static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
static void tomoyo_read_profile(struct tomoyo_io_buffer *head) static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
{ {
u8 index; u8 index;
struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
const struct tomoyo_profile *profile; const struct tomoyo_profile *profile;
if (head->r.eof)
return;
next: next:
index = head->r.index; index = head->r.index;
profile = tomoyo_profile_ptr[index]; profile = ns->profile_ptr[index];
switch (head->r.step) { switch (head->r.step) {
case 0: case 0:
tomoyo_io_printf(head, "PROFILE_VERSION=%u\n", 20090903); tomoyo_print_namespace(head);
tomoyo_io_printf(head, "PROFILE_VERSION=%u\n",
ns->profile_version);
head->r.step++; head->r.step++;
break; break;
case 1: case 1:
for ( ; head->r.index < TOMOYO_MAX_PROFILES; for ( ; head->r.index < TOMOYO_MAX_PROFILES;
head->r.index++) head->r.index++)
if (tomoyo_profile_ptr[head->r.index]) if (ns->profile_ptr[head->r.index])
break; break;
if (head->r.index == TOMOYO_MAX_PROFILES) if (head->r.index == TOMOYO_MAX_PROFILES)
return; return;
...@@ -541,6 +590,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) ...@@ -541,6 +590,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
u8 i; u8 i;
const struct tomoyo_path_info *comment = const struct tomoyo_path_info *comment =
profile->comment; profile->comment;
tomoyo_print_namespace(head);
tomoyo_io_printf(head, "%u-COMMENT=", index); tomoyo_io_printf(head, "%u-COMMENT=", index);
tomoyo_set_string(head, comment ? comment->name : ""); tomoyo_set_string(head, comment ? comment->name : "");
tomoyo_set_lf(head); tomoyo_set_lf(head);
...@@ -555,6 +605,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) ...@@ -555,6 +605,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
break; break;
case 3: case 3:
{ {
tomoyo_print_namespace(head);
tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); tomoyo_io_printf(head, "%u-%s", index, "CONFIG");
tomoyo_print_config(head, profile->default_config); tomoyo_print_config(head, profile->default_config);
head->r.bit = 0; head->r.bit = 0;
...@@ -568,6 +619,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) ...@@ -568,6 +619,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
const u8 config = profile->config[i]; const u8 config = profile->config[i];
if (config == TOMOYO_CONFIG_USE_DEFAULT) if (config == TOMOYO_CONFIG_USE_DEFAULT)
continue; continue;
tomoyo_print_namespace(head);
tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::", tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::",
tomoyo_mac_keywords[i]); tomoyo_mac_keywords[i]);
tomoyo_print_config(head, config); tomoyo_print_config(head, config);
...@@ -607,8 +659,10 @@ static int tomoyo_update_manager_entry(const char *manager, ...@@ -607,8 +659,10 @@ static int tomoyo_update_manager_entry(const char *manager,
{ {
struct tomoyo_manager e = { }; struct tomoyo_manager e = { };
struct tomoyo_acl_param param = { struct tomoyo_acl_param param = {
/* .ns = &tomoyo_kernel_namespace, */
.is_delete = is_delete, .is_delete = is_delete,
.list = &tomoyo_policy_list[TOMOYO_ID_MANAGER], .list = &tomoyo_kernel_namespace.
policy_list[TOMOYO_ID_MANAGER],
}; };
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
if (tomoyo_domain_def(manager)) { if (tomoyo_domain_def(manager)) {
...@@ -640,13 +694,12 @@ static int tomoyo_update_manager_entry(const char *manager, ...@@ -640,13 +694,12 @@ static int tomoyo_update_manager_entry(const char *manager,
static int tomoyo_write_manager(struct tomoyo_io_buffer *head) static int tomoyo_write_manager(struct tomoyo_io_buffer *head)
{ {
char *data = head->write_buf; char *data = head->write_buf;
bool is_delete = tomoyo_str_starts(&data, "delete ");
if (!strcmp(data, "manage_by_non_root")) { if (!strcmp(data, "manage_by_non_root")) {
tomoyo_manage_by_non_root = !is_delete; tomoyo_manage_by_non_root = !head->w.is_delete;
return 0; return 0;
} }
return tomoyo_update_manager_entry(data, is_delete); return tomoyo_update_manager_entry(data, head->w.is_delete);
} }
/** /**
...@@ -660,8 +713,8 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer *head) ...@@ -660,8 +713,8 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
{ {
if (head->r.eof) if (head->r.eof)
return; return;
list_for_each_cookie(head->r.acl, list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.
&tomoyo_policy_list[TOMOYO_ID_MANAGER]) { policy_list[TOMOYO_ID_MANAGER]) {
struct tomoyo_manager *ptr = struct tomoyo_manager *ptr =
list_entry(head->r.acl, typeof(*ptr), head.list); list_entry(head->r.acl, typeof(*ptr), head.list);
if (ptr->head.is_deleted) if (ptr->head.is_deleted)
...@@ -694,8 +747,8 @@ static bool tomoyo_manager(void) ...@@ -694,8 +747,8 @@ static bool tomoyo_manager(void)
return true; return true;
if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
return false; return false;
list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
head.list) { policy_list[TOMOYO_ID_MANAGER], head.list) {
if (!ptr->head.is_deleted && ptr->is_domain if (!ptr->head.is_deleted && ptr->is_domain
&& !tomoyo_pathcmp(domainname, ptr->manager)) { && !tomoyo_pathcmp(domainname, ptr->manager)) {
found = true; found = true;
...@@ -707,8 +760,8 @@ static bool tomoyo_manager(void) ...@@ -707,8 +760,8 @@ static bool tomoyo_manager(void)
exe = tomoyo_get_exe(); exe = tomoyo_get_exe();
if (!exe) if (!exe)
return false; return false;
list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
head.list) { policy_list[TOMOYO_ID_MANAGER], head.list) {
if (!ptr->head.is_deleted && !ptr->is_domain if (!ptr->head.is_deleted && !ptr->is_domain
&& !strcmp(exe, ptr->manager->name)) { && !strcmp(exe, ptr->manager->name)) {
found = true; found = true;
...@@ -729,7 +782,7 @@ static bool tomoyo_manager(void) ...@@ -729,7 +782,7 @@ static bool tomoyo_manager(void)
} }
/** /**
* tomoyo_select_one - Parse select command. * tomoyo_select_domain - Parse select command.
* *
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* @data: String to parse. * @data: String to parse.
...@@ -738,16 +791,15 @@ static bool tomoyo_manager(void) ...@@ -738,16 +791,15 @@ static bool tomoyo_manager(void)
* *
* Caller holds tomoyo_read_lock(). * Caller holds tomoyo_read_lock().
*/ */
static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
const char *data)
{ {
unsigned int pid; unsigned int pid;
struct tomoyo_domain_info *domain = NULL; struct tomoyo_domain_info *domain = NULL;
bool global_pid = false; bool global_pid = false;
if (strncmp(data, "select ", 7))
if (!strcmp(data, "allow_execute")) { return false;
head->r.print_execute_only = true; data += 7;
return true;
}
if (sscanf(data, "pid=%u", &pid) == 1 || if (sscanf(data, "pid=%u", &pid) == 1 ||
(global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
struct task_struct *p; struct task_struct *p;
...@@ -818,6 +870,7 @@ static int tomoyo_delete_domain(char *domainname) ...@@ -818,6 +870,7 @@ static int tomoyo_delete_domain(char *domainname)
/** /**
* tomoyo_write_domain2 - Write domain policy. * tomoyo_write_domain2 - Write domain policy.
* *
* @ns: Pointer to "struct tomoyo_policy_namespace".
* @list: Pointer to "struct list_head". * @list: Pointer to "struct list_head".
* @data: Policy to be interpreted. * @data: Policy to be interpreted.
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
...@@ -826,10 +879,12 @@ static int tomoyo_delete_domain(char *domainname) ...@@ -826,10 +879,12 @@ static int tomoyo_delete_domain(char *domainname)
* *
* Caller holds tomoyo_read_lock(). * Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_write_domain2(struct list_head *list, char *data, static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
struct list_head *list, char *data,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_acl_param param = { struct tomoyo_acl_param param = {
.ns = ns,
.list = list, .list = list,
.data = data, .data = data,
.is_delete = is_delete, .is_delete = is_delete,
...@@ -862,37 +917,28 @@ static int tomoyo_write_domain2(struct list_head *list, char *data, ...@@ -862,37 +917,28 @@ static int tomoyo_write_domain2(struct list_head *list, char *data,
static int tomoyo_write_domain(struct tomoyo_io_buffer *head) static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
{ {
char *data = head->write_buf; char *data = head->write_buf;
struct tomoyo_policy_namespace *ns;
struct tomoyo_domain_info *domain = head->w.domain; struct tomoyo_domain_info *domain = head->w.domain;
bool is_delete = false; const bool is_delete = head->w.is_delete;
bool is_select = false; bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
unsigned int profile; unsigned int profile;
if (*data == '<') {
if (tomoyo_str_starts(&data, "delete "))
is_delete = true;
else if (tomoyo_str_starts(&data, "select "))
is_select = true;
if (is_select && tomoyo_select_one(head, data))
return 0;
/* Don't allow updating policies by non manager programs. */
if (!tomoyo_manager())
return -EPERM;
if (tomoyo_domain_def(data)) {
domain = NULL; domain = NULL;
if (is_delete) if (is_delete)
tomoyo_delete_domain(data); tomoyo_delete_domain(data);
else if (is_select) else if (is_select)
domain = tomoyo_find_domain(data); domain = tomoyo_find_domain(data);
else else
domain = tomoyo_assign_domain(data, 0); domain = tomoyo_assign_domain(data, false);
head->w.domain = domain; head->w.domain = domain;
return 0; return 0;
} }
if (!domain) if (!domain)
return -EINVAL; return -EINVAL;
ns = domain->ns;
if (sscanf(data, "use_profile %u", &profile) == 1 if (sscanf(data, "use_profile %u", &profile) == 1
&& profile < TOMOYO_MAX_PROFILES) { && profile < TOMOYO_MAX_PROFILES) {
if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded) if (!tomoyo_policy_loaded || ns->profile_ptr[profile])
domain->profile = (u8) profile; domain->profile = (u8) profile;
return 0; return 0;
} }
...@@ -910,7 +956,8 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) ...@@ -910,7 +956,8 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
domain->transition_failed = !is_delete; domain->transition_failed = !is_delete;
return 0; return 0;
} }
return tomoyo_write_domain2(&domain->acl_info_list, data, is_delete); return tomoyo_write_domain2(ns, &domain->acl_info_list, data,
is_delete);
} }
/** /**
...@@ -924,9 +971,11 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) ...@@ -924,9 +971,11 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
static void tomoyo_set_group(struct tomoyo_io_buffer *head, static void tomoyo_set_group(struct tomoyo_io_buffer *head,
const char *category) const char *category)
{ {
if (head->type == TOMOYO_EXCEPTIONPOLICY) if (head->type == TOMOYO_EXCEPTIONPOLICY) {
tomoyo_print_namespace(head);
tomoyo_io_printf(head, "acl_group %u ", tomoyo_io_printf(head, "acl_group %u ",
head->r.acl_group_index); head->r.acl_group_index);
}
tomoyo_set_string(head, category); tomoyo_set_string(head, category);
} }
...@@ -956,7 +1005,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, ...@@ -956,7 +1005,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
if (!(perm & (1 << bit))) if (!(perm & (1 << bit)))
continue; continue;
if (head->r.print_execute_only && if (head->r.print_transition_related_only &&
bit != TOMOYO_TYPE_EXECUTE) bit != TOMOYO_TYPE_EXECUTE)
continue; continue;
if (first) { if (first) {
...@@ -970,7 +1019,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, ...@@ -970,7 +1019,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
if (first) if (first)
return true; return true;
tomoyo_print_name_union(head, &ptr->name); tomoyo_print_name_union(head, &ptr->name);
} else if (head->r.print_execute_only) { } else if (head->r.print_transition_related_only) {
return true; return true;
} else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
struct tomoyo_path2_acl *ptr = struct tomoyo_path2_acl *ptr =
...@@ -1147,8 +1196,8 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) ...@@ -1147,8 +1196,8 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
domain = tomoyo_find_domain(cp + 1); domain = tomoyo_find_domain(cp + 1);
if (strict_strtoul(data, 10, &profile)) if (strict_strtoul(data, 10, &profile))
return -EINVAL; return -EINVAL;
if (domain && profile < TOMOYO_MAX_PROFILES if (domain && (!tomoyo_policy_loaded ||
&& (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)) head->w.ns->profile_ptr[(u8) profile]))
domain->profile = (u8) profile; domain->profile = (u8) profile;
return 0; return 0;
} }
...@@ -1246,10 +1295,12 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) ...@@ -1246,10 +1295,12 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
} }
static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
[TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain", [TOMOYO_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ",
[TOMOYO_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain", [TOMOYO_TRANSITION_CONTROL_RESET] = "reset_domain ",
[TOMOYO_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain", [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
[TOMOYO_TRANSITION_CONTROL_KEEP] = "keep_domain", [TOMOYO_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
[TOMOYO_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
[TOMOYO_TRANSITION_CONTROL_KEEP] = "keep_domain ",
}; };
static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
...@@ -1268,19 +1319,13 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { ...@@ -1268,19 +1319,13 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
*/ */
static int tomoyo_write_exception(struct tomoyo_io_buffer *head) static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
{ {
const bool is_delete = head->w.is_delete;
struct tomoyo_acl_param param = { struct tomoyo_acl_param param = {
.ns = head->w.ns,
.is_delete = is_delete,
.data = head->write_buf, .data = head->write_buf,
}; };
u8 i; u8 i;
param.is_delete = tomoyo_str_starts(&param.data, "delete ");
if (!param.is_delete && tomoyo_str_starts(&param.data, "select ") &&
!strcmp(param.data, "execute_only")) {
head->r.print_execute_only = true;
return 0;
}
/* Don't allow updating policies by non manager programs. */
if (!tomoyo_manager())
return -EPERM;
if (tomoyo_str_starts(&param.data, "aggregator ")) if (tomoyo_str_starts(&param.data, "aggregator "))
return tomoyo_write_aggregator(&param); return tomoyo_write_aggregator(&param);
for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
...@@ -1294,8 +1339,9 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) ...@@ -1294,8 +1339,9 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
char *data; char *data;
group = simple_strtoul(param.data, &data, 10); group = simple_strtoul(param.data, &data, 10);
if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ')
return tomoyo_write_domain2(&tomoyo_acl_group[group], return tomoyo_write_domain2
data, param.is_delete); (head->w.ns, &head->w.ns->acl_group[group],
data, is_delete);
} }
return -EINVAL; return -EINVAL;
} }
...@@ -1312,7 +1358,10 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) ...@@ -1312,7 +1358,10 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
*/ */
static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
{ {
list_for_each_cookie(head->r.group, &tomoyo_group_list[idx]) { struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
struct list_head *list = &ns->group_list[idx];
list_for_each_cookie(head->r.group, list) {
struct tomoyo_group *group = struct tomoyo_group *group =
list_entry(head->r.group, typeof(*group), head.list); list_entry(head->r.group, typeof(*group), head.list);
list_for_each_cookie(head->r.acl, &group->member_list) { list_for_each_cookie(head->r.acl, &group->member_list) {
...@@ -1322,6 +1371,7 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) ...@@ -1322,6 +1371,7 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
continue; continue;
if (!tomoyo_flush(head)) if (!tomoyo_flush(head))
return false; return false;
tomoyo_print_namespace(head);
tomoyo_set_string(head, tomoyo_group_name[idx]); tomoyo_set_string(head, tomoyo_group_name[idx]);
tomoyo_set_string(head, group->group_name->name); tomoyo_set_string(head, group->group_name->name);
if (idx == TOMOYO_PATH_GROUP) { if (idx == TOMOYO_PATH_GROUP) {
...@@ -1355,7 +1405,10 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) ...@@ -1355,7 +1405,10 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
*/ */
static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
{ {
list_for_each_cookie(head->r.acl, &tomoyo_policy_list[idx]) { struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
struct list_head *list = &ns->policy_list[idx];
list_for_each_cookie(head->r.acl, list) {
struct tomoyo_acl_head *acl = struct tomoyo_acl_head *acl =
container_of(head->r.acl, typeof(*acl), list); container_of(head->r.acl, typeof(*acl), list);
if (acl->is_deleted) if (acl->is_deleted)
...@@ -1367,6 +1420,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) ...@@ -1367,6 +1420,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
{ {
struct tomoyo_transition_control *ptr = struct tomoyo_transition_control *ptr =
container_of(acl, typeof(*ptr), head); container_of(acl, typeof(*ptr), head);
tomoyo_print_namespace(head);
tomoyo_set_string(head, tomoyo_transition_type tomoyo_set_string(head, tomoyo_transition_type
[ptr->type]); [ptr->type]);
tomoyo_set_string(head, ptr->program ? tomoyo_set_string(head, ptr->program ?
...@@ -1381,6 +1435,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) ...@@ -1381,6 +1435,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
{ {
struct tomoyo_aggregator *ptr = struct tomoyo_aggregator *ptr =
container_of(acl, typeof(*ptr), head); container_of(acl, typeof(*ptr), head);
tomoyo_print_namespace(head);
tomoyo_set_string(head, "aggregator "); tomoyo_set_string(head, "aggregator ");
tomoyo_set_string(head, tomoyo_set_string(head,
ptr->original_name->name); ptr->original_name->name);
...@@ -1407,6 +1462,8 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) ...@@ -1407,6 +1462,8 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
*/ */
static void tomoyo_read_exception(struct tomoyo_io_buffer *head) static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
{ {
struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
if (head->r.eof) if (head->r.eof)
return; return;
while (head->r.step < TOMOYO_MAX_POLICY && while (head->r.step < TOMOYO_MAX_POLICY &&
...@@ -1423,7 +1480,7 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head) ...@@ -1423,7 +1480,7 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
+ TOMOYO_MAX_ACL_GROUPS) { + TOMOYO_MAX_ACL_GROUPS) {
head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY
- TOMOYO_MAX_GROUP; - TOMOYO_MAX_GROUP;
if (!tomoyo_read_domain2(head, &tomoyo_acl_group if (!tomoyo_read_domain2(head, &ns->acl_group
[head->r.acl_group_index])) [head->r.acl_group_index]))
return; return;
head->r.step++; head->r.step++;
...@@ -1484,7 +1541,8 @@ static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header) ...@@ -1484,7 +1541,8 @@ static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header)
return; return;
snprintf(buffer, len - 1, "%s", cp); snprintf(buffer, len - 1, "%s", cp);
tomoyo_normalize_line(buffer); tomoyo_normalize_line(buffer);
tomoyo_write_domain2(&domain->acl_info_list, buffer, false); tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer,
false);
kfree(buffer); kfree(buffer);
} }
...@@ -1895,6 +1953,45 @@ int tomoyo_poll_control(struct file *file, poll_table *wait) ...@@ -1895,6 +1953,45 @@ int tomoyo_poll_control(struct file *file, poll_table *wait)
return head->poll(file, wait); return head->poll(file, wait);
} }
/**
* tomoyo_set_namespace_cursor - Set namespace to read.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
* Returns nothing.
*/
static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head)
{
struct list_head *ns;
if (head->type != TOMOYO_EXCEPTIONPOLICY &&
head->type != TOMOYO_PROFILE)
return;
/*
* If this is the first read, or reading previous namespace finished
* and has more namespaces to read, update the namespace cursor.
*/
ns = head->r.ns;
if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) {
/* Clearing is OK because tomoyo_flush() returned true. */
memset(&head->r, 0, sizeof(head->r));
head->r.ns = ns ? ns->next : tomoyo_namespace_list.next;
}
}
/**
* tomoyo_has_more_namespace - Check for unread namespaces.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
* Returns true if we have more entries to print, false otherwise.
*/
static inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head)
{
return (head->type == TOMOYO_EXCEPTIONPOLICY ||
head->type == TOMOYO_PROFILE) && head->r.eof &&
head->r.ns->next != &tomoyo_namespace_list;
}
/** /**
* tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
* *
...@@ -1919,13 +2016,53 @@ int tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, ...@@ -1919,13 +2016,53 @@ int tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
head->read_user_buf_avail = buffer_len; head->read_user_buf_avail = buffer_len;
if (tomoyo_flush(head)) if (tomoyo_flush(head))
/* Call the policy handler. */ /* Call the policy handler. */
do {
tomoyo_set_namespace_cursor(head);
head->read(head); head->read(head);
tomoyo_flush(head); } while (tomoyo_flush(head) &&
tomoyo_has_more_namespace(head));
len = head->read_user_buf - buffer; len = head->read_user_buf - buffer;
mutex_unlock(&head->io_sem); mutex_unlock(&head->io_sem);
return len; return len;
} }
/**
* tomoyo_parse_policy - Parse a policy line.
*
* @head: Poiter to "struct tomoyo_io_buffer".
* @line: Line to parse.
*
* Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/
static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line)
{
/* Delete request? */
head->w.is_delete = !strncmp(line, "delete ", 7);
if (head->w.is_delete)
memmove(line, line + 7, strlen(line + 7) + 1);
/* Selecting namespace to update. */
if (head->type == TOMOYO_EXCEPTIONPOLICY ||
head->type == TOMOYO_PROFILE) {
if (*line == '<') {
char *cp = strchr(line, ' ');
if (cp) {
*cp++ = '\0';
head->w.ns = tomoyo_assign_namespace(line);
memmove(line, cp, strlen(cp) + 1);
} else
head->w.ns = NULL;
} else
head->w.ns = &tomoyo_kernel_namespace;
/* Don't allow updating if namespace is invalid. */
if (!head->w.ns)
return -ENOENT;
}
/* Do the update. */
return head->write(head);
}
/** /**
* tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface.
* *
...@@ -1941,27 +2078,31 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head, ...@@ -1941,27 +2078,31 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head,
const char __user *buffer, const int buffer_len) const char __user *buffer, const int buffer_len)
{ {
int error = buffer_len; int error = buffer_len;
int avail_len = buffer_len; size_t avail_len = buffer_len;
char *cp0 = head->write_buf; char *cp0 = head->write_buf;
if (!head->write) if (!head->write)
return -ENOSYS; return -ENOSYS;
if (!access_ok(VERIFY_READ, buffer, buffer_len)) if (!access_ok(VERIFY_READ, buffer, buffer_len))
return -EFAULT; return -EFAULT;
/* Don't allow updating policies by non manager programs. */
if (head->write != tomoyo_write_pid &&
head->write != tomoyo_write_domain &&
head->write != tomoyo_write_exception && !tomoyo_manager())
return -EPERM;
if (mutex_lock_interruptible(&head->io_sem)) if (mutex_lock_interruptible(&head->io_sem))
return -EINTR; return -EINTR;
/* Read a line and dispatch it to the policy handler. */ /* Read a line and dispatch it to the policy handler. */
while (avail_len > 0) { while (avail_len > 0) {
char c; char c;
if (head->w.avail >= head->writebuf_size - 1) { if (head->w.avail >= head->writebuf_size - 1) {
const int len = head->writebuf_size * 2;
char *cp = kzalloc(len, GFP_NOFS);
if (!cp) {
error = -ENOMEM; error = -ENOMEM;
break; break;
} else if (get_user(c, buffer)) { }
memmove(cp, cp0, head->w.avail);
kfree(cp0);
head->write_buf = cp;
cp0 = cp;
head->writebuf_size = len;
}
if (get_user(c, buffer)) {
error = -EFAULT; error = -EFAULT;
break; break;
} }
...@@ -1973,8 +2114,40 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head, ...@@ -1973,8 +2114,40 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head,
cp0[head->w.avail - 1] = '\0'; cp0[head->w.avail - 1] = '\0';
head->w.avail = 0; head->w.avail = 0;
tomoyo_normalize_line(cp0); tomoyo_normalize_line(cp0);
head->write(head); if (!strcmp(cp0, "reset")) {
head->w.ns = &tomoyo_kernel_namespace;
head->w.domain = NULL;
memset(&head->r, 0, sizeof(head->r));
continue;
}
/* Don't allow updating policies by non manager programs. */
switch (head->type) {
case TOMOYO_PROCESS_STATUS:
/* This does not write anything. */
break;
case TOMOYO_DOMAINPOLICY:
if (tomoyo_select_domain(head, cp0))
continue;
/* fall through */
case TOMOYO_EXCEPTIONPOLICY:
if (!strcmp(cp0, "select transition_only")) {
head->r.print_transition_related_only = true;
continue;
} }
/* fall through */
default:
if (!tomoyo_manager()) {
error = -EPERM;
goto out;
}
}
switch (tomoyo_parse_policy(head, cp0)) {
case -EPERM:
error = -EPERM;
goto out;
}
}
out:
mutex_unlock(&head->io_sem); mutex_unlock(&head->io_sem);
return error; return error;
} }
...@@ -2019,27 +2192,27 @@ void tomoyo_check_profile(void) ...@@ -2019,27 +2192,27 @@ void tomoyo_check_profile(void)
struct tomoyo_domain_info *domain; struct tomoyo_domain_info *domain;
const int idx = tomoyo_read_lock(); const int idx = tomoyo_read_lock();
tomoyo_policy_loaded = true; tomoyo_policy_loaded = true;
/* Check all profiles currently assigned to domains are defined. */ printk(KERN_INFO "TOMOYO: 2.4.0\n");
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
const u8 profile = domain->profile; const u8 profile = domain->profile;
if (tomoyo_profile_ptr[profile]) const struct tomoyo_policy_namespace *ns = domain->ns;
if (ns->profile_version != 20100903)
printk(KERN_ERR
"Profile version %u is not supported.\n",
ns->profile_version);
else if (!ns->profile_ptr[profile])
printk(KERN_ERR
"Profile %u (used by '%s') is not defined.\n",
profile, domain->domainname->name);
else
continue; continue;
printk(KERN_ERR "You need to define profile %u before using it.\n", printk(KERN_ERR
profile); "Userland tools for TOMOYO 2.4 must be installed and "
printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " "policy must be initialized.\n");
printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ "
"for more information.\n"); "for more information.\n");
panic("Profile %u (used by '%s') not defined.\n", panic("STOP!");
profile, domain->domainname->name);
} }
tomoyo_read_unlock(idx); tomoyo_read_unlock(idx);
if (tomoyo_profile_version != 20090903) {
printk(KERN_ERR "You need to install userland programs for "
"TOMOYO 2.3 and initialize policy configuration.\n");
printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ "
"for more information.\n");
panic("Profile version %u is not supported.\n",
tomoyo_profile_version);
}
printk(KERN_INFO "TOMOYO: 2.3.0\n");
printk(KERN_INFO "Mandatory Access Control activated.\n"); printk(KERN_INFO "Mandatory Access Control activated.\n");
} }
...@@ -74,10 +74,6 @@ enum tomoyo_group_id { ...@@ -74,10 +74,6 @@ enum tomoyo_group_id {
TOMOYO_MAX_GROUP TOMOYO_MAX_GROUP
}; };
/* A domain definition starts with <kernel>. */
#define TOMOYO_ROOT_NAME "<kernel>"
#define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1)
/* Index numbers for type of numeric values. */ /* Index numbers for type of numeric values. */
enum tomoyo_value_type { enum tomoyo_value_type {
TOMOYO_VALUE_TYPE_INVALID, TOMOYO_VALUE_TYPE_INVALID,
...@@ -89,6 +85,8 @@ enum tomoyo_value_type { ...@@ -89,6 +85,8 @@ enum tomoyo_value_type {
/* Index numbers for domain transition control keywords. */ /* Index numbers for domain transition control keywords. */
enum tomoyo_transition_type { enum tomoyo_transition_type {
/* Do not change this order, */ /* Do not change this order, */
TOMOYO_TRANSITION_CONTROL_NO_RESET,
TOMOYO_TRANSITION_CONTROL_RESET,
TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE, TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE,
TOMOYO_TRANSITION_CONTROL_INITIALIZE, TOMOYO_TRANSITION_CONTROL_INITIALIZE,
TOMOYO_TRANSITION_CONTROL_NO_KEEP, TOMOYO_TRANSITION_CONTROL_NO_KEEP,
...@@ -246,6 +244,8 @@ struct tomoyo_shared_acl_head { ...@@ -246,6 +244,8 @@ struct tomoyo_shared_acl_head {
atomic_t users; atomic_t users;
} __packed; } __packed;
struct tomoyo_policy_namespace;
/* Structure for request info. */ /* Structure for request info. */
struct tomoyo_request_info { struct tomoyo_request_info {
struct tomoyo_domain_info *domain; struct tomoyo_domain_info *domain;
...@@ -359,6 +359,8 @@ struct tomoyo_domain_info { ...@@ -359,6 +359,8 @@ struct tomoyo_domain_info {
struct list_head acl_info_list; struct list_head acl_info_list;
/* Name of this domain. Never NULL. */ /* Name of this domain. Never NULL. */
const struct tomoyo_path_info *domainname; const struct tomoyo_path_info *domainname;
/* Namespace for this domain. Never NULL. */
struct tomoyo_policy_namespace *ns;
u8 profile; /* Profile number to use. */ u8 profile; /* Profile number to use. */
u8 group; /* Group number to use. */ u8 group; /* Group number to use. */
bool is_deleted; /* Delete flag. */ bool is_deleted; /* Delete flag. */
...@@ -423,6 +425,7 @@ struct tomoyo_mount_acl { ...@@ -423,6 +425,7 @@ struct tomoyo_mount_acl {
struct tomoyo_acl_param { struct tomoyo_acl_param {
char *data; char *data;
struct list_head *list; struct list_head *list;
struct tomoyo_policy_namespace *ns;
bool is_delete; bool is_delete;
}; };
...@@ -443,6 +446,7 @@ struct tomoyo_io_buffer { ...@@ -443,6 +446,7 @@ struct tomoyo_io_buffer {
char __user *read_user_buf; char __user *read_user_buf;
int read_user_buf_avail; int read_user_buf_avail;
struct { struct {
struct list_head *ns;
struct list_head *domain; struct list_head *domain;
struct list_head *group; struct list_head *group;
struct list_head *acl; struct list_head *acl;
...@@ -455,14 +459,16 @@ struct tomoyo_io_buffer { ...@@ -455,14 +459,16 @@ struct tomoyo_io_buffer {
u8 w_pos; u8 w_pos;
bool eof; bool eof;
bool print_this_domain_only; bool print_this_domain_only;
bool print_execute_only; bool print_transition_related_only;
const char *w[TOMOYO_MAX_IO_READ_QUEUE]; const char *w[TOMOYO_MAX_IO_READ_QUEUE];
} r; } r;
struct { struct {
struct tomoyo_policy_namespace *ns;
/* The position currently writing to. */ /* The position currently writing to. */
struct tomoyo_domain_info *domain; struct tomoyo_domain_info *domain;
/* Bytes available for writing. */ /* Bytes available for writing. */
int avail; int avail;
bool is_delete;
} w; } w;
/* Buffer for reading. */ /* Buffer for reading. */
char *read_buf; char *read_buf;
...@@ -533,8 +539,27 @@ struct tomoyo_time { ...@@ -533,8 +539,27 @@ struct tomoyo_time {
u8 sec; u8 sec;
}; };
/* Structure for policy namespace. */
struct tomoyo_policy_namespace {
/* Profile table. Memory is allocated as needed. */
struct tomoyo_profile *profile_ptr[TOMOYO_MAX_PROFILES];
/* List of "struct tomoyo_group". */
struct list_head group_list[TOMOYO_MAX_GROUP];
/* List of policy. */
struct list_head policy_list[TOMOYO_MAX_POLICY];
/* The global ACL referred by "use_group" keyword. */
struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS];
/* List for connecting to tomoyo_namespace_list list. */
struct list_head namespace_list;
/* Profile version. Currently only 20100903 is defined. */
unsigned int profile_version;
/* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
const char *name;
};
/********** Function prototypes. **********/ /********** Function prototypes. **********/
void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns);
bool tomoyo_str_starts(char **src, const char *find); bool tomoyo_str_starts(char **src, const char *find);
const char *tomoyo_get_exe(void); const char *tomoyo_get_exe(void);
void tomoyo_normalize_line(unsigned char *buffer); void tomoyo_normalize_line(unsigned char *buffer);
...@@ -553,7 +578,8 @@ tomoyo_compare_name_union(const struct tomoyo_path_info *name, ...@@ -553,7 +578,8 @@ tomoyo_compare_name_union(const struct tomoyo_path_info *name,
const struct tomoyo_name_union *ptr); const struct tomoyo_name_union *ptr);
bool tomoyo_compare_number_union(const unsigned long value, bool tomoyo_compare_number_union(const unsigned long value,
const struct tomoyo_number_union *ptr); const struct tomoyo_number_union *ptr);
int tomoyo_get_mode(const u8 profile, const u8 index); int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
const u8 index);
void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3))); __attribute__ ((format(printf, 2, 3)));
bool tomoyo_correct_domain(const unsigned char *domainname); bool tomoyo_correct_domain(const unsigned char *domainname);
...@@ -589,8 +615,11 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) ...@@ -589,8 +615,11 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3))); __attribute__ ((format(printf, 2, 3)));
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
const bool transit);
struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
const u8 profile); const u8 profile);
struct tomoyo_profile *tomoyo_profile(const u8 profile); struct tomoyo_policy_namespace *tomoyo_assign_namespace
(const char *domainname);
struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
const u8 idx); const u8 idx);
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
...@@ -646,6 +675,8 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param); ...@@ -646,6 +675,8 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param);
bool tomoyo_permstr(const char *string, const char *keyword); bool tomoyo_permstr(const char *string, const char *keyword);
const char *tomoyo_yesno(const unsigned int value); const char *tomoyo_yesno(const unsigned int value);
void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
va_list args); va_list args);
void tomoyo_read_log(struct tomoyo_io_buffer *head); void tomoyo_read_log(struct tomoyo_io_buffer *head);
...@@ -661,8 +692,6 @@ extern struct srcu_struct tomoyo_ss; ...@@ -661,8 +692,6 @@ extern struct srcu_struct tomoyo_ss;
/* The list for "struct tomoyo_domain_info". */ /* The list for "struct tomoyo_domain_info". */
extern struct list_head tomoyo_domain_list; extern struct list_head tomoyo_domain_list;
extern struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
extern struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
/* Lock for protecting policy. */ /* Lock for protecting policy. */
...@@ -671,10 +700,10 @@ extern struct mutex tomoyo_policy_lock; ...@@ -671,10 +700,10 @@ extern struct mutex tomoyo_policy_lock;
/* Has /sbin/init started? */ /* Has /sbin/init started? */
extern bool tomoyo_policy_loaded; extern bool tomoyo_policy_loaded;
extern struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS];
/* The kernel's domain. */ /* The kernel's domain. */
extern struct tomoyo_domain_info tomoyo_kernel_domain; extern struct tomoyo_domain_info tomoyo_kernel_domain;
extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
extern struct list_head tomoyo_namespace_list;
extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION]; extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION];
...@@ -809,6 +838,16 @@ static inline bool tomoyo_same_number_union ...@@ -809,6 +838,16 @@ static inline bool tomoyo_same_number_union
a->value_type[1] == b->value_type[1]; a->value_type[1] == b->value_type[1];
} }
/**
* tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread.
*
* Returns pointer to "struct tomoyo_policy_namespace" for current thread.
*/
static inline struct tomoyo_policy_namespace *tomoyo_current_namespace(void)
{
return tomoyo_domain()->ns;
}
#if defined(CONFIG_SLOB) #if defined(CONFIG_SLOB)
/** /**
......
...@@ -12,9 +12,6 @@ ...@@ -12,9 +12,6 @@
/* Variables definitions.*/ /* Variables definitions.*/
/* The global ACL referred by "use_group" keyword. */
struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS];
/* The initial domain. */ /* The initial domain. */
struct tomoyo_domain_info tomoyo_kernel_domain; struct tomoyo_domain_info tomoyo_kernel_domain;
...@@ -158,7 +155,7 @@ void tomoyo_check_acl(struct tomoyo_request_info *r, ...@@ -158,7 +155,7 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
} }
if (!retried) { if (!retried) {
retried = true; retried = true;
list = &tomoyo_acl_group[domain->group]; list = &domain->ns->acl_group[domain->group];
goto retry; goto retry;
} }
r->granted = false; r->granted = false;
...@@ -167,13 +164,10 @@ void tomoyo_check_acl(struct tomoyo_request_info *r, ...@@ -167,13 +164,10 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
/* The list for "struct tomoyo_domain_info". */ /* The list for "struct tomoyo_domain_info". */
LIST_HEAD(tomoyo_domain_list); LIST_HEAD(tomoyo_domain_list);
struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
/** /**
* tomoyo_last_word - Get last component of a domainname. * tomoyo_last_word - Get last component of a domainname.
* *
* @domainname: Domainname to check. * @name: Domainname to check.
* *
* Returns the last word of @domainname. * Returns the last word of @domainname.
*/ */
...@@ -247,7 +241,7 @@ int tomoyo_write_transition_control(struct tomoyo_acl_param *param, ...@@ -247,7 +241,7 @@ int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
if (!e.domainname) if (!e.domainname)
goto out; goto out;
} }
param->list = &tomoyo_policy_list[TOMOYO_ID_TRANSITION_CONTROL]; param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
error = tomoyo_update_policy(&e.head, sizeof(e), param, error = tomoyo_update_policy(&e.head, sizeof(e), param,
tomoyo_same_transition_control); tomoyo_same_transition_control);
out: out:
...@@ -257,28 +251,25 @@ int tomoyo_write_transition_control(struct tomoyo_acl_param *param, ...@@ -257,28 +251,25 @@ int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
} }
/** /**
* tomoyo_transition_type - Get domain transition type. * tomoyo_scan_transition - Try to find specific domain transition type.
* *
* @domainname: The name of domain. * @list: Pointer to "struct list_head".
* @program: The name of program. * @domainname: The name of current domain.
* @program: The name of requested program.
* @last_name: The last component of @domainname.
* @type: One of values in "enum tomoyo_transition_type".
* *
* Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program * Returns true if found one, false otherwise.
* reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
* @program suppresses domain transition, others otherwise.
* *
* Caller holds tomoyo_read_lock(). * Caller holds tomoyo_read_lock().
*/ */
static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, static inline bool tomoyo_scan_transition
const struct tomoyo_path_info *program) (const struct list_head *list, const struct tomoyo_path_info *domainname,
const struct tomoyo_path_info *program, const char *last_name,
const enum tomoyo_transition_type type)
{ {
const struct tomoyo_transition_control *ptr; const struct tomoyo_transition_control *ptr;
const char *last_name = tomoyo_last_word(domainname->name); list_for_each_entry_rcu(ptr, list, head.list) {
u8 type;
for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) {
next:
list_for_each_entry_rcu(ptr, &tomoyo_policy_list
[TOMOYO_ID_TRANSITION_CONTROL],
head.list) {
if (ptr->head.is_deleted || ptr->type != type) if (ptr->head.is_deleted || ptr->type != type)
continue; continue;
if (ptr->domainname) { if (ptr->domainname) {
...@@ -290,26 +281,58 @@ static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, ...@@ -290,26 +281,58 @@ static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname,
* Use direct strcmp() since this is * Use direct strcmp() since this is
* unlikely used. * unlikely used.
*/ */
if (strcmp(ptr->domainname->name, if (strcmp(ptr->domainname->name, last_name))
last_name))
continue; continue;
} }
} }
if (ptr->program && if (ptr->program && tomoyo_pathcmp(ptr->program, program))
tomoyo_pathcmp(ptr->program, program))
continue; continue;
if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) { return true;
/*
* Do not check for initialize_domain if
* no_initialize_domain matched.
*/
type = TOMOYO_TRANSITION_CONTROL_NO_KEEP;
goto next;
} }
goto done; return false;
}
/**
* tomoyo_transition_type - Get domain transition type.
*
* @ns: Pointer to "struct tomoyo_policy_namespace".
* @domainname: The name of current domain.
* @program: The name of requested program.
*
* Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes
* domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if
* executing @program reinitializes domain transition within that namespace,
* TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
* others otherwise.
*
* Caller holds tomoyo_read_lock().
*/
static enum tomoyo_transition_type tomoyo_transition_type
(const struct tomoyo_policy_namespace *ns,
const struct tomoyo_path_info *domainname,
const struct tomoyo_path_info *program)
{
const char *last_name = tomoyo_last_word(domainname->name);
enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
while (type < TOMOYO_MAX_TRANSITION_TYPE) {
const struct list_head * const list =
&ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
if (!tomoyo_scan_transition(list, domainname, program,
last_name, type)) {
type++;
continue;
} }
if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET &&
type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE)
break;
/*
* Do not check for reset_domain if no_reset_domain matched.
* Do not check for initialize_domain if no_initialize_domain
* matched.
*/
type++;
type++;
} }
done:
return type; return type;
} }
...@@ -355,7 +378,7 @@ int tomoyo_write_aggregator(struct tomoyo_acl_param *param) ...@@ -355,7 +378,7 @@ int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
if (!e.original_name || !e.aggregated_name || if (!e.original_name || !e.aggregated_name ||
e.aggregated_name->is_patterned) /* No patterns allowed. */ e.aggregated_name->is_patterned) /* No patterns allowed. */
goto out; goto out;
param->list = &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR]; param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
error = tomoyo_update_policy(&e.head, sizeof(e), param, error = tomoyo_update_policy(&e.head, sizeof(e), param,
tomoyo_same_aggregator); tomoyo_same_aggregator);
out: out:
...@@ -365,53 +388,171 @@ int tomoyo_write_aggregator(struct tomoyo_acl_param *param) ...@@ -365,53 +388,171 @@ int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
} }
/** /**
* tomoyo_assign_domain - Create a domain. * tomoyo_find_namespace - Find specified namespace.
*
* @name: Name of namespace to find.
* @len: Length of @name.
*
* Returns pointer to "struct tomoyo_policy_namespace" if found,
* NULL otherwise.
*
* Caller holds tomoyo_read_lock().
*/
static struct tomoyo_policy_namespace *tomoyo_find_namespace
(const char *name, const unsigned int len)
{
struct tomoyo_policy_namespace *ns;
list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
if (strncmp(name, ns->name, len) ||
(name[len] && name[len] != ' '))
continue;
return ns;
}
return NULL;
}
/**
* tomoyo_assign_namespace - Create a new namespace.
*
* @domainname: Name of namespace to create.
*
* Returns pointer to "struct tomoyo_policy_namespace" on success,
* NULL otherwise.
*
* Caller holds tomoyo_read_lock().
*/
struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
{
struct tomoyo_policy_namespace *ptr;
struct tomoyo_policy_namespace *entry;
const char *cp = domainname;
unsigned int len = 0;
while (*cp && *cp++ != ' ')
len++;
ptr = tomoyo_find_namespace(domainname, len);
if (ptr)
return ptr;
if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname))
return NULL;
entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
if (!entry)
return NULL;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
ptr = tomoyo_find_namespace(domainname, len);
if (!ptr && tomoyo_memory_ok(entry)) {
char *name = (char *) (entry + 1);
ptr = entry;
memmove(name, domainname, len);
name[len] = '\0';
entry->name = name;
tomoyo_init_policy_namespace(entry);
entry = NULL;
}
mutex_unlock(&tomoyo_policy_lock);
out:
kfree(entry);
return ptr;
}
/**
* tomoyo_namespace_jump - Check for namespace jump.
*
* @domainname: Name of domain.
*
* Returns true if namespace differs, false otherwise.
*/
static bool tomoyo_namespace_jump(const char *domainname)
{
const char *namespace = tomoyo_current_namespace()->name;
const int len = strlen(namespace);
return strncmp(domainname, namespace, len) ||
(domainname[len] && domainname[len] != ' ');
}
/**
* tomoyo_assign_domain - Create a domain or a namespace.
* *
* @domainname: The name of domain. * @domainname: The name of domain.
* @profile: Profile number to assign if the domain was newly created. * @transit: True if transit to domain found or created.
* *
* Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
* *
* Caller holds tomoyo_read_lock(). * Caller holds tomoyo_read_lock().
*/ */
struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
const u8 profile) const bool transit)
{ {
struct tomoyo_domain_info *entry; struct tomoyo_domain_info e = { };
struct tomoyo_domain_info *domain = NULL; struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
const struct tomoyo_path_info *saved_domainname; bool created = false;
bool found = false; if (entry) {
if (transit) {
if (!tomoyo_correct_domain(domainname)) /*
* Since namespace is created at runtime, profiles may
* not be created by the moment the process transits to
* that domain. Do not perform domain transition if
* profile for that domain is not yet created.
*/
if (!entry->ns->profile_ptr[entry->profile])
return NULL;
}
return entry;
}
/* Requested domain does not exist. */
/* Don't create requested domain if domainname is invalid. */
if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
!tomoyo_correct_domain(domainname))
return NULL; return NULL;
saved_domainname = tomoyo_get_name(domainname); /*
if (!saved_domainname) * Since definition of profiles and acl_groups may differ across
* namespaces, do not inherit "use_profile" and "use_group" settings
* by automatically creating requested domain upon domain transition.
*/
if (transit && tomoyo_namespace_jump(domainname))
return NULL;
e.ns = tomoyo_assign_namespace(domainname);
if (!e.ns)
return NULL;
/*
* "use_profile" and "use_group" settings for automatically created
* domains are inherited from current domain. These are 0 for manually
* created domains.
*/
if (transit) {
const struct tomoyo_domain_info *domain = tomoyo_domain();
e.profile = domain->profile;
e.group = domain->group;
}
e.domainname = tomoyo_get_name(domainname);
if (!e.domainname)
return NULL; return NULL;
entry = kzalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { entry = tomoyo_find_domain(domainname);
if (domain->is_deleted || if (!entry) {
tomoyo_pathcmp(saved_domainname, domain->domainname)) entry = tomoyo_commit_ok(&e, sizeof(e));
continue; if (entry) {
found = true;
break;
}
if (!found && tomoyo_memory_ok(entry)) {
INIT_LIST_HEAD(&entry->acl_info_list); INIT_LIST_HEAD(&entry->acl_info_list);
entry->domainname = saved_domainname;
saved_domainname = NULL;
entry->profile = profile;
list_add_tail_rcu(&entry->list, &tomoyo_domain_list); list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
domain = entry; created = true;
entry = NULL; }
found = true;
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_domainname); tomoyo_put_name(e.domainname);
kfree(entry); if (entry && transit) {
return found ? domain : NULL; if (created) {
struct tomoyo_request_info r;
tomoyo_init_request_info(&r, entry,
TOMOYO_MAC_FILE_EXECUTE);
r.granted = false;
tomoyo_write_log(&r, "use_profile %u\n",
entry->profile);
tomoyo_write_log(&r, "use_group %u\n", entry->group);
}
}
return entry;
} }
/** /**
...@@ -434,6 +575,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -434,6 +575,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
bool is_enforce; bool is_enforce;
int retval = -ENOMEM; int retval = -ENOMEM;
bool need_kfree = false; bool need_kfree = false;
bool reject_on_transition_failure = false;
struct tomoyo_path_info rn = { }; /* real name */ struct tomoyo_path_info rn = { }; /* real name */
mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); 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,8 +599,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
/* Check 'aggregator' directive. */ /* Check 'aggregator' directive. */
{ {
struct tomoyo_aggregator *ptr; struct tomoyo_aggregator *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_policy_list struct list_head *list =
[TOMOYO_ID_AGGREGATOR], head.list) { &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
/* Check 'aggregator' directive. */
list_for_each_entry_rcu(ptr, list, head.list) {
if (ptr->head.is_deleted || if (ptr->head.is_deleted ||
!tomoyo_path_matches_pattern(&rn, !tomoyo_path_matches_pattern(&rn,
ptr->original_name)) ptr->original_name))
...@@ -492,11 +636,21 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -492,11 +636,21 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
} }
/* Calculate domain to transit to. */ /* Calculate domain to transit to. */
switch (tomoyo_transition_type(old_domain->domainname, &rn)) { switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
&rn)) {
case TOMOYO_TRANSITION_CONTROL_RESET:
/* Transit to the root of specified namespace. */
snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
/*
* Make do_execve() fail if domain transition across namespaces
* has failed.
*/
reject_on_transition_failure = true;
break;
case TOMOYO_TRANSITION_CONTROL_INITIALIZE: case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
/* Transit to the child of tomoyo_kernel_domain domain. */ /* Transit to the child of current namespace's root. */
snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " " snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
"%s", rn.name); old_domain->ns->name, rn.name);
break; break;
case TOMOYO_TRANSITION_CONTROL_KEEP: case TOMOYO_TRANSITION_CONTROL_KEEP:
/* Keep current domain. */ /* Keep current domain. */
...@@ -519,19 +673,25 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -519,19 +673,25 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
} }
break; break;
} }
if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
goto done;
domain = tomoyo_find_domain(tmp);
if (!domain) if (!domain)
domain = tomoyo_assign_domain(tmp, old_domain->profile); domain = tomoyo_assign_domain(tmp, true);
done:
if (domain) if (domain)
goto out; retval = 0;
printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp); else if (reject_on_transition_failure) {
if (is_enforce) printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", tmp);
retval = -EPERM; retval = -ENOMEM;
else } else if (r.mode == TOMOYO_CONFIG_ENFORCING)
retval = -ENOMEM;
else {
retval = 0;
if (!old_domain->transition_failed) {
old_domain->transition_failed = true; old_domain->transition_failed = true;
r.granted = false;
tomoyo_write_log(&r, "%s", "transition_failed\n");
printk(KERN_WARNING
"ERROR: Domain '%s' not defined.\n", tmp);
}
}
out: out:
if (!domain) if (!domain)
domain = old_domain; domain = old_domain;
......
...@@ -603,7 +603,7 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, ...@@ -603,7 +603,7 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
int error; int error;
r->type = tomoyo_p2mac[operation]; r->type = tomoyo_p2mac[operation];
r->mode = tomoyo_get_mode(r->profile, r->type); r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
if (r->mode == TOMOYO_CONFIG_DISABLED) if (r->mode == TOMOYO_CONFIG_DISABLED)
return 0; return 0;
r->param_type = TOMOYO_TYPE_PATH_ACL; r->param_type = TOMOYO_TYPE_PATH_ACL;
......
...@@ -292,15 +292,12 @@ static bool tomoyo_collect_acl(struct list_head *list) ...@@ -292,15 +292,12 @@ static bool tomoyo_collect_acl(struct list_head *list)
static void tomoyo_collect_entry(void) static void tomoyo_collect_entry(void)
{ {
int i; int i;
enum tomoyo_policy_id id;
struct tomoyo_policy_namespace *ns;
int idx;
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
return; return;
for (i = 0; i < TOMOYO_MAX_POLICY; i++) { idx = tomoyo_read_lock();
if (!tomoyo_collect_member(i, &tomoyo_policy_list[i]))
goto unlock;
}
for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
if (!tomoyo_collect_acl(&tomoyo_acl_group[i]))
goto unlock;
{ {
struct tomoyo_domain_info *domain; struct tomoyo_domain_info *domain;
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
...@@ -317,18 +314,15 @@ static void tomoyo_collect_entry(void) ...@@ -317,18 +314,15 @@ static void tomoyo_collect_entry(void)
goto unlock; goto unlock;
} }
} }
for (i = 0; i < TOMOYO_MAX_HASH; i++) { list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) {
struct tomoyo_name *ptr; for (id = 0; id < TOMOYO_MAX_POLICY; id++)
list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], head.list) { if (!tomoyo_collect_member(id, &ns->policy_list[id]))
if (atomic_read(&ptr->head.users)) goto unlock;
continue; for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->head.list)) if (!tomoyo_collect_acl(&ns->acl_group[i]))
goto unlock; goto unlock;
}
}
for (i = 0; i < TOMOYO_MAX_GROUP; i++) { for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
struct list_head *list = &tomoyo_group_list[i]; struct list_head *list = &ns->group_list[i];
int id;
struct tomoyo_group *group; struct tomoyo_group *group;
switch (i) { switch (i) {
case 0: case 0:
...@@ -339,7 +333,8 @@ static void tomoyo_collect_entry(void) ...@@ -339,7 +333,8 @@ static void tomoyo_collect_entry(void)
break; break;
} }
list_for_each_entry(group, list, head.list) { list_for_each_entry(group, list, head.list) {
if (!tomoyo_collect_member(id, &group->member_list)) if (!tomoyo_collect_member
(id, &group->member_list))
goto unlock; goto unlock;
if (!list_empty(&group->member_list) || if (!list_empty(&group->member_list) ||
atomic_read(&group->head.users)) atomic_read(&group->head.users))
...@@ -349,7 +344,19 @@ static void tomoyo_collect_entry(void) ...@@ -349,7 +344,19 @@ static void tomoyo_collect_entry(void)
goto unlock; goto unlock;
} }
} }
unlock: }
for (i = 0; i < TOMOYO_MAX_HASH; i++) {
struct list_head *list = &tomoyo_name_list[i];
struct tomoyo_shared_acl_head *ptr;
list_for_each_entry(ptr, list, list) {
if (atomic_read(&ptr->users))
continue;
if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
goto unlock;
}
}
unlock:
tomoyo_read_unlock(idx);
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
} }
......
...@@ -118,7 +118,7 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, ...@@ -118,7 +118,7 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
return NULL; return NULL;
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
list = &tomoyo_group_list[idx]; list = &param->ns->group_list[idx];
list_for_each_entry(group, list, head.list) { list_for_each_entry(group, list, head.list) {
if (e.group_name != group->group_name) if (e.group_name != group->group_name)
continue; continue;
...@@ -199,27 +199,23 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) ...@@ -199,27 +199,23 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
return ptr ? &ptr->entry : NULL; return ptr ? &ptr->entry : NULL;
} }
/* Initial namespace.*/
struct tomoyo_policy_namespace tomoyo_kernel_namespace;
/** /**
* tomoyo_mm_init - Initialize mm related code. * tomoyo_mm_init - Initialize mm related code.
*/ */
void __init tomoyo_mm_init(void) void __init tomoyo_mm_init(void)
{ {
int idx; int idx;
for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
INIT_LIST_HEAD(&tomoyo_policy_list[idx]);
for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
INIT_LIST_HEAD(&tomoyo_group_list[idx]);
for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
INIT_LIST_HEAD(&tomoyo_name_list[idx]); INIT_LIST_HEAD(&tomoyo_name_list[idx]);
tomoyo_kernel_namespace.name = "<kernel>";
tomoyo_init_policy_namespace(&tomoyo_kernel_namespace);
tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace;
INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>");
INIT_LIST_HEAD(&tomoyo_acl_group[idx]);
tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
idx = tomoyo_read_lock();
if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
panic("Can't register tomoyo_kernel_domain");
#if 0 #if 0
/* Will be replaced with tomoyo_load_builtin_policy(). */ /* Will be replaced with tomoyo_load_builtin_policy(). */
{ {
...@@ -230,7 +226,6 @@ void __init tomoyo_mm_init(void) ...@@ -230,7 +226,6 @@ void __init tomoyo_mm_init(void)
TOMOYO_TRANSITION_CONTROL_INITIALIZE); TOMOYO_TRANSITION_CONTROL_INITIALIZE);
} }
#endif #endif
tomoyo_read_unlock(idx);
} }
......
...@@ -416,26 +416,21 @@ bool tomoyo_correct_path(const char *filename) ...@@ -416,26 +416,21 @@ bool tomoyo_correct_path(const char *filename)
*/ */
bool tomoyo_correct_domain(const unsigned char *domainname) bool tomoyo_correct_domain(const unsigned char *domainname)
{ {
if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, if (!domainname || !tomoyo_domain_def(domainname))
TOMOYO_ROOT_NAME_LEN)) return false;
goto out; domainname = strchr(domainname, ' ');
domainname += TOMOYO_ROOT_NAME_LEN; if (!domainname++)
if (!*domainname)
return true; return true;
if (*domainname++ != ' ')
goto out;
while (1) { while (1) {
const unsigned char *cp = strchr(domainname, ' '); const unsigned char *cp = strchr(domainname, ' ');
if (!cp) if (!cp)
break; break;
if (*domainname != '/' || if (*domainname != '/' ||
!tomoyo_correct_word2(domainname, cp - domainname)) !tomoyo_correct_word2(domainname, cp - domainname))
goto out; return false;
domainname = cp + 1; domainname = cp + 1;
} }
return tomoyo_correct_path(domainname); return tomoyo_correct_path(domainname);
out:
return false;
} }
/** /**
...@@ -447,7 +442,19 @@ bool tomoyo_correct_domain(const unsigned char *domainname) ...@@ -447,7 +442,19 @@ bool tomoyo_correct_domain(const unsigned char *domainname)
*/ */
bool tomoyo_domain_def(const unsigned char *buffer) bool tomoyo_domain_def(const unsigned char *buffer)
{ {
return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN); const unsigned char *cp;
int len;
if (*buffer != '<')
return false;
cp = strchr(buffer, ' ');
if (!cp)
len = strlen(buffer);
else
len = cp - buffer;
if (buffer[len - 1] != '>' ||
!tomoyo_correct_word2(buffer + 1, len - 2))
return false;
return true;
} }
/** /**
...@@ -833,22 +840,24 @@ const char *tomoyo_get_exe(void) ...@@ -833,22 +840,24 @@ const char *tomoyo_get_exe(void)
/** /**
* tomoyo_get_mode - Get MAC mode. * tomoyo_get_mode - Get MAC mode.
* *
* @ns: Pointer to "struct tomoyo_policy_namespace".
* @profile: Profile number. * @profile: Profile number.
* @index: Index number of functionality. * @index: Index number of functionality.
* *
* Returns mode. * Returns mode.
*/ */
int tomoyo_get_mode(const u8 profile, const u8 index) int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
const u8 index)
{ {
u8 mode; u8 mode;
const u8 category = TOMOYO_MAC_CATEGORY_FILE; const u8 category = TOMOYO_MAC_CATEGORY_FILE;
if (!tomoyo_policy_loaded) if (!tomoyo_policy_loaded)
return TOMOYO_CONFIG_DISABLED; return TOMOYO_CONFIG_DISABLED;
mode = tomoyo_profile(profile)->config[index]; mode = tomoyo_profile(ns, profile)->config[index];
if (mode == TOMOYO_CONFIG_USE_DEFAULT) if (mode == TOMOYO_CONFIG_USE_DEFAULT)
mode = tomoyo_profile(profile)->config[category]; mode = tomoyo_profile(ns, profile)->config[category];
if (mode == TOMOYO_CONFIG_USE_DEFAULT) if (mode == TOMOYO_CONFIG_USE_DEFAULT)
mode = tomoyo_profile(profile)->default_config; mode = tomoyo_profile(ns, profile)->default_config;
return mode & 3; return mode & 3;
} }
...@@ -872,25 +881,10 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, ...@@ -872,25 +881,10 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r,
profile = domain->profile; profile = domain->profile;
r->profile = profile; r->profile = profile;
r->type = index; r->type = index;
r->mode = tomoyo_get_mode(profile, index); r->mode = tomoyo_get_mode(domain->ns, profile, index);
return r->mode; return r->mode;
} }
/**
* tomoyo_last_word - Get last component of a line.
*
* @line: A line.
*
* Returns the last word of a line.
*/
const char *tomoyo_last_word(const char *name)
{
const char *cp = strrchr(name, ' ');
if (cp)
return cp + 1;
return name;
}
/** /**
* tomoyo_domain_quota_is_ok - Check for domain's quota. * tomoyo_domain_quota_is_ok - Check for domain's quota.
* *
...@@ -939,7 +933,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) ...@@ -939,7 +933,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
if (perm & (1 << i)) if (perm & (1 << i))
count++; count++;
} }
if (count < tomoyo_profile(domain->profile)-> if (count < tomoyo_profile(domain->ns, domain->profile)->
pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) pref[TOMOYO_PREF_MAX_LEARNING_ENTRY])
return true; return true;
if (!domain->quota_warned) { if (!domain->quota_warned) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment