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;
/**
* tomoyo_get_audit - Get audit mode.
*
* @ns: Pointer to "struct tomoyo_policy_namespace".
* @profile: Profile number.
* @index: Index number of functionality.
* @is_granted: True if granted log, 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)
{
u8 mode;
......@@ -165,7 +167,7 @@ static bool tomoyo_get_audit(const u8 profile, const u8 index,
struct tomoyo_profile *p;
if (!tomoyo_policy_loaded)
return false;
p = tomoyo_profile(profile);
p = tomoyo_profile(ns, profile);
if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
return false;
mode = p->config[index];
......@@ -194,7 +196,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
char *buf;
struct tomoyo_log *entry;
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;
buf = tomoyo_init_log(r, len, fmt, args);
if (!buf)
......
This diff is collapsed.
......@@ -74,10 +74,6 @@ enum tomoyo_group_id {
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. */
enum tomoyo_value_type {
TOMOYO_VALUE_TYPE_INVALID,
......@@ -89,6 +85,8 @@ enum tomoyo_value_type {
/* Index numbers for domain transition control keywords. */
enum tomoyo_transition_type {
/* Do not change this order, */
TOMOYO_TRANSITION_CONTROL_NO_RESET,
TOMOYO_TRANSITION_CONTROL_RESET,
TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE,
TOMOYO_TRANSITION_CONTROL_INITIALIZE,
TOMOYO_TRANSITION_CONTROL_NO_KEEP,
......@@ -246,6 +244,8 @@ struct tomoyo_shared_acl_head {
atomic_t users;
} __packed;
struct tomoyo_policy_namespace;
/* Structure for request info. */
struct tomoyo_request_info {
struct tomoyo_domain_info *domain;
......@@ -359,6 +359,8 @@ struct tomoyo_domain_info {
struct list_head acl_info_list;
/* Name of this domain. Never NULL. */
const struct tomoyo_path_info *domainname;
/* Namespace for this domain. Never NULL. */
struct tomoyo_policy_namespace *ns;
u8 profile; /* Profile number to use. */
u8 group; /* Group number to use. */
bool is_deleted; /* Delete flag. */
......@@ -423,6 +425,7 @@ struct tomoyo_mount_acl {
struct tomoyo_acl_param {
char *data;
struct list_head *list;
struct tomoyo_policy_namespace *ns;
bool is_delete;
};
......@@ -443,6 +446,7 @@ struct tomoyo_io_buffer {
char __user *read_user_buf;
int read_user_buf_avail;
struct {
struct list_head *ns;
struct list_head *domain;
struct list_head *group;
struct list_head *acl;
......@@ -455,14 +459,16 @@ struct tomoyo_io_buffer {
u8 w_pos;
bool eof;
bool print_this_domain_only;
bool print_execute_only;
bool print_transition_related_only;
const char *w[TOMOYO_MAX_IO_READ_QUEUE];
} r;
struct {
struct tomoyo_policy_namespace *ns;
/* The position currently writing to. */
struct tomoyo_domain_info *domain;
/* Bytes available for writing. */
int avail;
bool is_delete;
} w;
/* Buffer for reading. */
char *read_buf;
......@@ -533,8 +539,27 @@ struct tomoyo_time {
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. **********/
void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns);
bool tomoyo_str_starts(char **src, const char *find);
const char *tomoyo_get_exe(void);
void tomoyo_normalize_line(unsigned char *buffer);
......@@ -553,7 +578,8 @@ tomoyo_compare_name_union(const struct tomoyo_path_info *name,
const struct tomoyo_name_union *ptr);
bool tomoyo_compare_number_union(const unsigned long value,
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, ...)
__attribute__ ((format(printf, 2, 3)));
bool tomoyo_correct_domain(const unsigned char *domainname);
......@@ -589,8 +615,11 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
const u8 profile);
struct tomoyo_profile *tomoyo_profile(const u8 profile);
const bool transit);
struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
const u8 profile);
struct tomoyo_policy_namespace *tomoyo_assign_namespace
(const char *domainname);
struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
const u8 idx);
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
......@@ -646,6 +675,8 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param);
bool tomoyo_permstr(const char *string, const char *keyword);
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,
va_list args);
void tomoyo_read_log(struct tomoyo_io_buffer *head);
......@@ -661,8 +692,6 @@ extern struct srcu_struct tomoyo_ss;
/* The list for "struct tomoyo_domain_info". */
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];
/* Lock for protecting policy. */
......@@ -671,10 +700,10 @@ extern struct mutex tomoyo_policy_lock;
/* Has /sbin/init started? */
extern bool tomoyo_policy_loaded;
extern struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS];
/* The kernel's 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_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION];
......@@ -809,6 +838,16 @@ static inline bool tomoyo_same_number_union
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)
/**
......
This diff is collapsed.
......@@ -603,7 +603,7 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
int error;
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)
return 0;
r->param_type = TOMOYO_TYPE_PATH_ACL;
......
......@@ -292,15 +292,12 @@ static bool tomoyo_collect_acl(struct list_head *list)
static void tomoyo_collect_entry(void)
{
int i;
enum tomoyo_policy_id id;
struct tomoyo_policy_namespace *ns;
int idx;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
return;
for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
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;
idx = tomoyo_read_lock();
{
struct tomoyo_domain_info *domain;
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
......@@ -317,39 +314,49 @@ static void tomoyo_collect_entry(void)
goto unlock;
}
}
for (i = 0; i < TOMOYO_MAX_HASH; i++) {
struct tomoyo_name *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], head.list) {
if (atomic_read(&ptr->head.users))
continue;
if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->head.list))
list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) {
for (id = 0; id < TOMOYO_MAX_POLICY; id++)
if (!tomoyo_collect_member(id, &ns->policy_list[id]))
goto unlock;
for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
if (!tomoyo_collect_acl(&ns->acl_group[i]))
goto unlock;
for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
struct list_head *list = &ns->group_list[i];
struct tomoyo_group *group;
switch (i) {
case 0:
id = TOMOYO_ID_PATH_GROUP;
break;
default:
id = TOMOYO_ID_NUMBER_GROUP;
break;
}
list_for_each_entry(group, list, head.list) {
if (!tomoyo_collect_member
(id, &group->member_list))
goto unlock;
if (!list_empty(&group->member_list) ||
atomic_read(&group->head.users))
continue;
if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP,
&group->head.list))
goto unlock;
}
}
}
for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
struct list_head *list = &tomoyo_group_list[i];
int id;
struct tomoyo_group *group;
switch (i) {
case 0:
id = TOMOYO_ID_PATH_GROUP;
break;
default:
id = TOMOYO_ID_NUMBER_GROUP;
break;
}
list_for_each_entry(group, list, head.list) {
if (!tomoyo_collect_member(id, &group->member_list))
goto unlock;
if (!list_empty(&group->member_list) ||
atomic_read(&group->head.users))
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_GROUP,
&group->head.list))
if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
goto unlock;
}
}
unlock:
unlock:
tomoyo_read_unlock(idx);
mutex_unlock(&tomoyo_policy_lock);
}
......
......@@ -118,7 +118,7 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
return NULL;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
list = &tomoyo_group_list[idx];
list = &param->ns->group_list[idx];
list_for_each_entry(group, list, head.list) {
if (e.group_name != group->group_name)
continue;
......@@ -199,27 +199,23 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
return ptr ? &ptr->entry : NULL;
}
/* Initial namespace.*/
struct tomoyo_policy_namespace tomoyo_kernel_namespace;
/**
* tomoyo_mm_init - Initialize mm related code.
*/
void __init tomoyo_mm_init(void)
{
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++)
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);
for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
INIT_LIST_HEAD(&tomoyo_acl_group[idx]);
tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>");
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
/* Will be replaced with tomoyo_load_builtin_policy(). */
{
......@@ -230,7 +226,6 @@ void __init tomoyo_mm_init(void)
TOMOYO_TRANSITION_CONTROL_INITIALIZE);
}
#endif
tomoyo_read_unlock(idx);
}
......
......@@ -416,26 +416,21 @@ bool tomoyo_correct_path(const char *filename)
*/
bool tomoyo_correct_domain(const unsigned char *domainname)
{
if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
TOMOYO_ROOT_NAME_LEN))
goto out;
domainname += TOMOYO_ROOT_NAME_LEN;
if (!*domainname)
if (!domainname || !tomoyo_domain_def(domainname))
return false;
domainname = strchr(domainname, ' ');
if (!domainname++)
return true;
if (*domainname++ != ' ')
goto out;
while (1) {
const unsigned char *cp = strchr(domainname, ' ');
if (!cp)
break;
if (*domainname != '/' ||
!tomoyo_correct_word2(domainname, cp - domainname))
goto out;
return false;
domainname = cp + 1;
}
return tomoyo_correct_path(domainname);
out:
return false;
}
/**
......@@ -447,7 +442,19 @@ bool tomoyo_correct_domain(const unsigned char *domainname)
*/
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)
/**
* tomoyo_get_mode - Get MAC mode.
*
* @ns: Pointer to "struct tomoyo_policy_namespace".
* @profile: Profile number.
* @index: Index number of functionality.
*
* 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;
const u8 category = TOMOYO_MAC_CATEGORY_FILE;
if (!tomoyo_policy_loaded)
return TOMOYO_CONFIG_DISABLED;
mode = tomoyo_profile(profile)->config[index];
mode = tomoyo_profile(ns, profile)->config[index];
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)
mode = tomoyo_profile(profile)->default_config;
mode = tomoyo_profile(ns, profile)->default_config;
return mode & 3;
}
......@@ -872,25 +881,10 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r,
profile = domain->profile;
r->profile = profile;
r->type = index;
r->mode = tomoyo_get_mode(profile, index);
r->mode = tomoyo_get_mode(domain->ns, profile, index);
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.
*
......@@ -939,7 +933,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
if (perm & (1 << i))
count++;
}
if (count < tomoyo_profile(domain->profile)->
if (count < tomoyo_profile(domain->ns, domain->profile)->
pref[TOMOYO_PREF_MAX_LEARNING_ENTRY])
return true;
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