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

TOMOYO: Add ACL group support.

ACL group allows administrator to globally grant not only "file read"
permission but also other permissions.
Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent eadd99cc
...@@ -896,6 +896,12 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) ...@@ -896,6 +896,12 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
domain->profile = (u8) profile; domain->profile = (u8) profile;
return 0; return 0;
} }
if (sscanf(data, "use_group %u\n", &profile) == 1
&& profile < TOMOYO_MAX_ACL_GROUPS) {
if (!is_delete)
domain->group = (u8) profile;
return 0;
}
if (!strcmp(data, "quota_exceeded")) { if (!strcmp(data, "quota_exceeded")) {
domain->quota_warned = !is_delete; domain->quota_warned = !is_delete;
return 0; return 0;
...@@ -908,7 +914,7 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) ...@@ -908,7 +914,7 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
} }
/** /**
* tomoyo_set_group - Print category name. * tomoyo_set_group - Print "acl_group " header keyword and category name.
* *
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* @category: Category name. * @category: Category name.
...@@ -918,6 +924,9 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) ...@@ -918,6 +924,9 @@ 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)
tomoyo_io_printf(head, "acl_group %u ",
head->r.acl_group_index);
tomoyo_set_string(head, category); tomoyo_set_string(head, category);
} }
...@@ -1042,16 +1051,16 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, ...@@ -1042,16 +1051,16 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
* tomoyo_read_domain2 - Read domain policy. * tomoyo_read_domain2 - Read domain policy.
* *
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* @domain: Pointer to "struct tomoyo_domain_info". * @list: Pointer to "struct list_head".
* *
* Caller holds tomoyo_read_lock(). * Caller holds tomoyo_read_lock().
* *
* Returns true on success, false otherwise. * Returns true on success, false otherwise.
*/ */
static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
struct tomoyo_domain_info *domain) struct list_head *list)
{ {
list_for_each_cookie(head->r.acl, &domain->acl_info_list) { list_for_each_cookie(head->r.acl, list) {
struct tomoyo_acl_info *ptr = struct tomoyo_acl_info *ptr =
list_entry(head->r.acl, typeof(*ptr), list); list_entry(head->r.acl, typeof(*ptr), list);
if (!tomoyo_print_entry(head, ptr)) if (!tomoyo_print_entry(head, ptr))
...@@ -1085,6 +1094,8 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) ...@@ -1085,6 +1094,8 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
tomoyo_set_lf(head); tomoyo_set_lf(head);
tomoyo_io_printf(head, "use_profile %u\n", tomoyo_io_printf(head, "use_profile %u\n",
domain->profile); domain->profile);
tomoyo_io_printf(head, "use_group %u\n",
domain->group);
if (domain->quota_warned) if (domain->quota_warned)
tomoyo_set_string(head, "quota_exceeded\n"); tomoyo_set_string(head, "quota_exceeded\n");
if (domain->transition_failed) if (domain->transition_failed)
...@@ -1093,7 +1104,7 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) ...@@ -1093,7 +1104,7 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
tomoyo_set_lf(head); tomoyo_set_lf(head);
/* fall through */ /* fall through */
case 1: case 1:
if (!tomoyo_read_domain2(head, domain)) if (!tomoyo_read_domain2(head, &domain->acl_info_list))
return; return;
head->r.step++; head->r.step++;
if (!tomoyo_set_lf(head)) if (!tomoyo_set_lf(head))
...@@ -1262,6 +1273,14 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) ...@@ -1262,6 +1273,14 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
}; };
u8 i; u8 i;
param.is_delete = tomoyo_str_starts(&param.data, "delete "); 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++)
...@@ -1270,6 +1289,14 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) ...@@ -1270,6 +1289,14 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
for (i = 0; i < TOMOYO_MAX_GROUP; i++) for (i = 0; i < TOMOYO_MAX_GROUP; i++)
if (tomoyo_str_starts(&param.data, tomoyo_group_name[i])) if (tomoyo_str_starts(&param.data, tomoyo_group_name[i]))
return tomoyo_write_group(&param, i); return tomoyo_write_group(&param, i);
if (tomoyo_str_starts(&param.data, "acl_group ")) {
unsigned int group;
char *data;
group = simple_strtoul(param.data, &data, 10);
if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ')
return tomoyo_write_domain2(&tomoyo_acl_group[group],
data, param.is_delete);
}
return -EINVAL; return -EINVAL;
} }
...@@ -1392,6 +1419,15 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head) ...@@ -1392,6 +1419,15 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
head->r.step++; head->r.step++;
if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
return; return;
while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP
+ TOMOYO_MAX_ACL_GROUPS) {
head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY
- TOMOYO_MAX_GROUP;
if (!tomoyo_read_domain2(head, &tomoyo_acl_group
[head->r.acl_group_index]))
return;
head->r.step++;
}
head->r.eof = true; head->r.eof = true;
} }
...@@ -1914,7 +1950,8 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head, ...@@ -1914,7 +1950,8 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head,
return -EFAULT; return -EFAULT;
/* Don't allow updating policies by non manager programs. */ /* Don't allow updating policies by non manager programs. */
if (head->write != tomoyo_write_pid && if (head->write != tomoyo_write_pid &&
head->write != tomoyo_write_domain && !tomoyo_manager()) head->write != tomoyo_write_domain &&
head->write != tomoyo_write_exception && !tomoyo_manager())
return -EPERM; return -EPERM;
if (mutex_lock_interruptible(&head->io_sem)) if (mutex_lock_interruptible(&head->io_sem))
return -EINTR; return -EINTR;
......
...@@ -38,6 +38,9 @@ struct linux_binprm; ...@@ -38,6 +38,9 @@ struct linux_binprm;
/* Profile number is an integer between 0 and 255. */ /* Profile number is an integer between 0 and 255. */
#define TOMOYO_MAX_PROFILES 256 #define TOMOYO_MAX_PROFILES 256
/* Group number is an integer between 0 and 255. */
#define TOMOYO_MAX_ACL_GROUPS 256
/* Index numbers for operation mode. */ /* Index numbers for operation mode. */
enum tomoyo_mode_index { enum tomoyo_mode_index {
TOMOYO_CONFIG_DISABLED, TOMOYO_CONFIG_DISABLED,
...@@ -357,6 +360,7 @@ struct tomoyo_domain_info { ...@@ -357,6 +360,7 @@ struct tomoyo_domain_info {
/* Name of this domain. Never NULL. */ /* Name of this domain. Never NULL. */
const struct tomoyo_path_info *domainname; const struct tomoyo_path_info *domainname;
u8 profile; /* Profile number to use. */ u8 profile; /* Profile number to use. */
u8 group; /* Group number to use. */
bool is_deleted; /* Delete flag. */ bool is_deleted; /* Delete flag. */
bool quota_warned; /* Quota warnning flag. */ bool quota_warned; /* Quota warnning flag. */
bool transition_failed; /* Domain transition failed flag. */ bool transition_failed; /* Domain transition failed flag. */
...@@ -446,6 +450,7 @@ struct tomoyo_io_buffer { ...@@ -446,6 +450,7 @@ struct tomoyo_io_buffer {
int step; int step;
int query_index; int query_index;
u16 index; u16 index;
u8 acl_group_index;
u8 bit; u8 bit;
u8 w_pos; u8 w_pos;
bool eof; bool eof;
...@@ -666,6 +671,8 @@ extern struct mutex tomoyo_policy_lock; ...@@ -666,6 +671,8 @@ 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;
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
/* 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;
...@@ -125,14 +128,27 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, ...@@ -125,14 +128,27 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
return error; return error;
} }
/**
* tomoyo_check_acl - Do permission check.
*
* @r: Pointer to "struct tomoyo_request_info".
* @check_entry: Callback function to check type specific parameters.
*
* Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/
void tomoyo_check_acl(struct tomoyo_request_info *r, void tomoyo_check_acl(struct tomoyo_request_info *r,
bool (*check_entry) (struct tomoyo_request_info *, bool (*check_entry) (struct tomoyo_request_info *,
const struct tomoyo_acl_info *)) const struct tomoyo_acl_info *))
{ {
const struct tomoyo_domain_info *domain = r->domain; const struct tomoyo_domain_info *domain = r->domain;
struct tomoyo_acl_info *ptr; struct tomoyo_acl_info *ptr;
bool retried = false;
const struct list_head *list = &domain->acl_info_list;
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { retry:
list_for_each_entry_rcu(ptr, list, list) {
if (ptr->is_deleted || ptr->type != r->param_type) if (ptr->is_deleted || ptr->type != r->param_type)
continue; continue;
if (check_entry(r, ptr)) { if (check_entry(r, ptr)) {
...@@ -140,6 +156,11 @@ void tomoyo_check_acl(struct tomoyo_request_info *r, ...@@ -140,6 +156,11 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
return; return;
} }
} }
if (!retried) {
retried = true;
list = &tomoyo_acl_group[domain->group];
goto retry;
}
r->granted = false; r->granted = false;
} }
......
...@@ -265,10 +265,17 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id, ...@@ -265,10 +265,17 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id,
return true; return true;
} }
static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain) /**
* tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info".
*
* @list: Pointer to "struct list_head".
*
* Returns true if some elements are deleted, false otherwise.
*/
static bool tomoyo_collect_acl(struct list_head *list)
{ {
struct tomoyo_acl_info *acl; struct tomoyo_acl_info *acl;
list_for_each_entry(acl, &domain->acl_info_list, list) { list_for_each_entry(acl, list, list) {
if (!acl->is_deleted) if (!acl->is_deleted)
continue; continue;
if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
...@@ -291,10 +298,13 @@ static void tomoyo_collect_entry(void) ...@@ -291,10 +298,13 @@ static void tomoyo_collect_entry(void)
if (!tomoyo_collect_member(i, &tomoyo_policy_list[i])) if (!tomoyo_collect_member(i, &tomoyo_policy_list[i]))
goto unlock; 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) {
if (!tomoyo_collect_acl(domain)) if (!tomoyo_collect_acl(&domain->acl_info_list))
goto unlock; goto unlock;
if (!domain->is_deleted || atomic_read(&domain->users)) if (!domain->is_deleted || atomic_read(&domain->users))
continue; continue;
......
...@@ -213,6 +213,8 @@ void __init tomoyo_mm_init(void) ...@@ -213,6 +213,8 @@ void __init tomoyo_mm_init(void)
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]);
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++)
INIT_LIST_HEAD(&tomoyo_acl_group[idx]);
tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); 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(); idx = tomoyo_read_lock();
......
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