TOMOYO: Add ACL group support.
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>
This commit is contained in:
Родитель
eadd99cc85
Коммит
32997144fd
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -1042,16 +1051,16 @@ 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".
|
||||
* @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))
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -1262,6 +1273,14 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
|
|||
};
|
||||
u8 i;
|
||||
param.is_delete = tomoyo_str_starts(¶m.data, "delete ");
|
||||
if (!param.is_delete && tomoyo_str_starts(¶m.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(¶m.data, "aggregator "))
|
||||
return tomoyo_write_aggregator(¶m);
|
||||
for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
|
||||
|
@ -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(¶m.data, tomoyo_group_name[i]))
|
||||
return tomoyo_write_group(¶m, i);
|
||||
if (tomoyo_str_starts(¶m.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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -125,14 +128,27 @@ 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)) {
|
||||
|
@ -140,6 +156,11 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (!retried) {
|
||||
retried = true;
|
||||
list = &tomoyo_acl_group[domain->group];
|
||||
goto retry;
|
||||
}
|
||||
r->granted = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче