Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+44 −7
Original line number Diff line number Diff line
@@ -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(&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++)
@@ -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;
}

@@ -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;
+7 −0
Original line number Diff line number Diff line
@@ -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;

+22 −1
Original line number Diff line number Diff line
@@ -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;
}

+13 −3
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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();