Skip to content

Commit

Permalink
TOMOYO: Add ACL group support.
Browse files Browse the repository at this point in the history
ACL group allows administrator to globally grant not only "file read"
permission but also other permissions.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
  • Loading branch information
Tetsuo Handa authored and James Morris committed Jun 28, 2011
1 parent eadd99c commit 3299714
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 11 deletions.
51 changes: 44 additions & 7 deletions security/tomoyo/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,12 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
domain->profile = (u8) profile;
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")) {
domain->quota_warned = !is_delete;
return 0;
Expand All @@ -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".
* @category: Category name.
Expand All @@ -918,6 +924,9 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
static void tomoyo_set_group(struct tomoyo_io_buffer *head,
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);
}

Expand Down Expand Up @@ -1041,17 +1050,17 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
/**
* tomoyo_read_domain2 - Read domain policy.
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @domain: Pointer to "struct tomoyo_domain_info".
* @head: Pointer to "struct tomoyo_io_buffer".
* @list: Pointer to "struct list_head".
*
* Caller holds tomoyo_read_lock().
*
* Returns true on success, false otherwise.
*/
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 =
list_entry(head->r.acl, typeof(*ptr), list);
if (!tomoyo_print_entry(head, ptr))
Expand Down Expand Up @@ -1085,6 +1094,8 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
tomoyo_set_lf(head);
tomoyo_io_printf(head, "use_profile %u\n",
domain->profile);
tomoyo_io_printf(head, "use_group %u\n",
domain->group);
if (domain->quota_warned)
tomoyo_set_string(head, "quota_exceeded\n");
if (domain->transition_failed)
Expand All @@ -1093,7 +1104,7 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
tomoyo_set_lf(head);
/* fall through */
case 1:
if (!tomoyo_read_domain2(head, domain))
if (!tomoyo_read_domain2(head, &domain->acl_info_list))
return;
head->r.step++;
if (!tomoyo_set_lf(head))
Expand Down Expand Up @@ -1262,6 +1273,14 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
};
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 "))
return tomoyo_write_aggregator(&param);
for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
Expand All @@ -1270,6 +1289,14 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
for (i = 0; i < TOMOYO_MAX_GROUP; i++)
if (tomoyo_str_starts(&param.data, tomoyo_group_name[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;
}

Expand Down Expand Up @@ -1392,6 +1419,15 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
head->r.step++;
if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
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;
}

Expand Down Expand Up @@ -1914,7 +1950,8 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head,
return -EFAULT;
/* Don't allow updating policies by non manager programs. */
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;
if (mutex_lock_interruptible(&head->io_sem))
return -EINTR;
Expand Down
7 changes: 7 additions & 0 deletions security/tomoyo/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ struct linux_binprm;
/* Profile number is an integer between 0 and 255. */
#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. */
enum tomoyo_mode_index {
TOMOYO_CONFIG_DISABLED,
Expand Down Expand Up @@ -357,6 +360,7 @@ struct tomoyo_domain_info {
/* Name of this domain. Never NULL. */
const struct tomoyo_path_info *domainname;
u8 profile; /* Profile number to use. */
u8 group; /* Group number to use. */
bool is_deleted; /* Delete flag. */
bool quota_warned; /* Quota warnning flag. */
bool transition_failed; /* Domain transition failed flag. */
Expand Down Expand Up @@ -446,6 +450,7 @@ struct tomoyo_io_buffer {
int step;
int query_index;
u16 index;
u8 acl_group_index;
u8 bit;
u8 w_pos;
bool eof;
Expand Down Expand Up @@ -666,6 +671,8 @@ 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;

Expand Down
23 changes: 22 additions & 1 deletion security/tomoyo/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

/* Variables definitions.*/

/* The global ACL referred by "use_group" keyword. */
struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS];

/* The initial domain. */
struct tomoyo_domain_info tomoyo_kernel_domain;

Expand Down Expand Up @@ -125,21 +128,39 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
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,
bool (*check_entry) (struct tomoyo_request_info *,
const struct tomoyo_acl_info *))
{
const struct tomoyo_domain_info *domain = r->domain;
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)
continue;
if (check_entry(r, ptr)) {
r->granted = true;
return;
}
}
if (!retried) {
retried = true;
list = &tomoyo_acl_group[domain->group];
goto retry;
}
r->granted = false;
}

Expand Down
16 changes: 13 additions & 3 deletions security/tomoyo/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,17 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id,
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;
list_for_each_entry(acl, &domain->acl_info_list, list) {
list_for_each_entry(acl, list, list) {
if (!acl->is_deleted)
continue;
if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
Expand All @@ -291,10 +298,13 @@ static void tomoyo_collect_entry(void)
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;
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;
if (!domain->is_deleted || atomic_read(&domain->users))
continue;
Expand Down
2 changes: 2 additions & 0 deletions security/tomoyo/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ void __init tomoyo_mm_init(void)
for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
INIT_LIST_HEAD(&tomoyo_name_list[idx]);
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);
list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
idx = tomoyo_read_lock();
Expand Down

0 comments on commit 3299714

Please sign in to comment.