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;
}
/**
- * 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.
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);
}
/**
* 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))
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)
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))
};
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++)
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;
}
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;
}
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;
/* 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,
/* 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. */
int step;
int query_index;
u16 index;
+ u8 acl_group_index;
u8 bit;
u8 w_pos;
bool eof;
/* 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;
/* 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;
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)) {
return;
}
}
+ if (!retried) {
+ retried = true;
+ list = &tomoyo_acl_group[domain->group];
+ goto retry;
+ }
r->granted = false;
}
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))
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;