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

TOMOYO: Allow using UID/GID etc. of current thread as conditions.



This patch adds support for permission checks using current thread's UID/GID
etc. in addition to pathnames.

Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 5c4274f1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
obj-y = audit.o common.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
obj-y = audit.o common.o condition.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o

$(obj)/policy/profile.conf:
	@mkdir -p $(obj)/policy/
+16 −16
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
	const pid_t gpid = task_pid_nr(current);
	static const int tomoyo_buffer_len = 4096;
	char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
	pid_t ppid;
	int pos;
	if (!buffer)
		return NULL;
	{
@@ -33,21 +33,21 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
		do_gettimeofday(&tv);
		tomoyo_convert_time(tv.tv_sec, &stamp);
	}
	rcu_read_lock();
	ppid = task_tgid_vnr(current->real_parent);
	rcu_read_unlock();
	snprintf(buffer, tomoyo_buffer_len - 1,
	pos = snprintf(buffer, tomoyo_buffer_len - 1,
		       "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
		       "granted=%s (global-pid=%u) task={ pid=%u ppid=%u "
		       "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u "
		 "fsuid=%u fsgid=%u }",
		 stamp.year, stamp.month, stamp.day, stamp.hour,
		 stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode],
		 tomoyo_yesno(r->granted), gpid, task_tgid_vnr(current), ppid,
		 current_uid(), current_gid(), current_euid(), current_egid(),
		 current_suid(), current_sgid(), current_fsuid(),
		 current_fsgid());
		       "fsuid=%u fsgid=%u }", stamp.year, stamp.month,
		       stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile,
		       tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid,
		       tomoyo_sys_getpid(), tomoyo_sys_getppid(),
		       current_uid(), current_gid(), current_euid(),
		       current_egid(), current_suid(), current_sgid(),
		       current_fsuid(), current_fsgid());
	if (pos < tomoyo_buffer_len - 1)
		return buffer;
	kfree(buffer);
	return NULL;
}

/**
+137 −9
Original line number Diff line number Diff line
@@ -48,6 +48,20 @@ const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
};

/* String table for conditions. */
const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = {
	[TOMOYO_TASK_UID]             = "task.uid",
	[TOMOYO_TASK_EUID]            = "task.euid",
	[TOMOYO_TASK_SUID]            = "task.suid",
	[TOMOYO_TASK_FSUID]           = "task.fsuid",
	[TOMOYO_TASK_GID]             = "task.gid",
	[TOMOYO_TASK_EGID]            = "task.egid",
	[TOMOYO_TASK_SGID]            = "task.sgid",
	[TOMOYO_TASK_FSGID]           = "task.fsgid",
	[TOMOYO_TASK_PID]             = "task.pid",
	[TOMOYO_TASK_PPID]            = "task.ppid",
};

/* String table for PREFERENCE keyword. */
static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = {
	[TOMOYO_PREF_MAX_AUDIT_LOG]      = "max_audit_log",
@@ -294,15 +308,16 @@ static void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
}

/**
 * tomoyo_print_number_union - Print a tomoyo_number_union.
 * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 * @ptr:  Pointer to "struct tomoyo_number_union".
 *
 * Returns nothing.
 */
static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
				      const struct tomoyo_number_union *ptr)
static void tomoyo_print_number_union_nospace
(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr)
{
	tomoyo_set_space(head);
	if (ptr->group) {
		tomoyo_set_string(head, "@");
		tomoyo_set_string(head, ptr->group->group_name->name);
@@ -325,8 +340,8 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
						 "0%lo", min);
				break;
			default:
				tomoyo_addprintf(buffer, sizeof(buffer),
						 "%lu", min);
				tomoyo_addprintf(buffer, sizeof(buffer), "%lu",
						 min);
				break;
			}
			if (min == max && min_type == max_type)
@@ -339,6 +354,21 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
	}
}

/**
 * tomoyo_print_number_union - Print a tomoyo_number_union.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 * @ptr:  Pointer to "struct tomoyo_number_union".
 *
 * Returns nothing.
 */
static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
				      const struct tomoyo_number_union *ptr)
{
	tomoyo_set_space(head);
	tomoyo_print_number_union_nospace(head, ptr);
}

/**
 * tomoyo_assign_profile - Create a new profile.
 *
@@ -1003,6 +1033,91 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
				    is_delete);
}

/**
 * tomoyo_print_condition - Print condition part.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 * @cond: Pointer to "struct tomoyo_condition".
 *
 * Returns true on success, false otherwise.
 */
static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
				   const struct tomoyo_condition *cond)
{
	switch (head->r.cond_step) {
	case 0:
		head->r.cond_index = 0;
		head->r.cond_step++;
		/* fall through */
	case 1:
		{
			const u16 condc = cond->condc;
			const struct tomoyo_condition_element *condp =
				(typeof(condp)) (cond + 1);
			const struct tomoyo_number_union *numbers_p =
				(typeof(numbers_p)) (condp + condc);
			u16 skip;
			for (skip = 0; skip < head->r.cond_index; skip++) {
				const u8 left = condp->left;
				const u8 right = condp->right;
				condp++;
				switch (left) {
				case TOMOYO_NUMBER_UNION:
					numbers_p++;
					break;
				}
				switch (right) {
				case TOMOYO_NUMBER_UNION:
					numbers_p++;
					break;
				}
			}
			while (head->r.cond_index < condc) {
				const u8 match = condp->equals;
				const u8 left = condp->left;
				const u8 right = condp->right;
				if (!tomoyo_flush(head))
					return false;
				condp++;
				head->r.cond_index++;
				tomoyo_set_space(head);
				switch (left) {
				case TOMOYO_NUMBER_UNION:
					tomoyo_print_number_union_nospace
						(head, numbers_p++);
					break;
				default:
					tomoyo_set_string(head,
					       tomoyo_condition_keyword[left]);
					break;
				}
				tomoyo_set_string(head, match ? "=" : "!=");
				switch (right) {
				case TOMOYO_NUMBER_UNION:
					tomoyo_print_number_union_nospace
						(head, numbers_p++);
					break;
				default:
					tomoyo_set_string(head,
					  tomoyo_condition_keyword[right]);
					break;
				}
			}
		}
		head->r.cond_step++;
		/* fall through */
	case 2:
		if (!tomoyo_flush(head))
			break;
		head->r.cond_step++;
		/* fall through */
	case 3:
		tomoyo_set_lf(head);
		return true;
	}
	return false;
}

/**
 * tomoyo_set_group - Print "acl_group " header keyword and category name.
 *
@@ -1037,6 +1152,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
	bool first = true;
	u8 bit;

	if (head->r.print_cond_part)
		goto print_cond_part;
	if (acl->is_deleted)
		return true;
	if (!tomoyo_flush(head))
@@ -1135,7 +1252,18 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
		tomoyo_print_name_union(head, &ptr->fs_type);
		tomoyo_print_number_union(head, &ptr->flags);
	}
	if (acl->cond) {
		head->r.print_cond_part = true;
		head->r.cond_step = 0;
		if (!tomoyo_flush(head))
			return false;
print_cond_part:
		if (!tomoyo_print_condition(head, acl->cond))
			return false;
		head->r.print_cond_part = false;
	} else {
		tomoyo_set_lf(head);
	}
	return true;
}

+96 −1
Original line number Diff line number Diff line
@@ -21,7 +21,8 @@
#include <linux/list.h>
#include <linux/cred.h>
#include <linux/poll.h>
struct linux_binprm;
#include <linux/binfmts.h>
#include <linux/highmem.h>

/********** Constants definitions. **********/

@@ -41,6 +42,22 @@ struct linux_binprm;
/* Group number is an integer between 0 and 255. */
#define TOMOYO_MAX_ACL_GROUPS 256

/* Index numbers for "struct tomoyo_condition". */
enum tomoyo_conditions_index {
	TOMOYO_TASK_UID,             /* current_uid()   */
	TOMOYO_TASK_EUID,            /* current_euid()  */
	TOMOYO_TASK_SUID,            /* current_suid()  */
	TOMOYO_TASK_FSUID,           /* current_fsuid() */
	TOMOYO_TASK_GID,             /* current_gid()   */
	TOMOYO_TASK_EGID,            /* current_egid()  */
	TOMOYO_TASK_SGID,            /* current_sgid()  */
	TOMOYO_TASK_FSGID,           /* current_fsgid() */
	TOMOYO_TASK_PID,             /* sys_getpid()   */
	TOMOYO_TASK_PPID,            /* sys_getppid()  */
	TOMOYO_MAX_CONDITION_KEYWORD,
	TOMOYO_NUMBER_UNION,
};

/* Index numbers for operation mode. */
enum tomoyo_mode_index {
	TOMOYO_CONFIG_DISABLED,
@@ -61,6 +78,7 @@ enum tomoyo_policy_id {
	TOMOYO_ID_TRANSITION_CONTROL,
	TOMOYO_ID_AGGREGATOR,
	TOMOYO_ID_MANAGER,
	TOMOYO_ID_CONDITION,
	TOMOYO_ID_NAME,
	TOMOYO_ID_ACL,
	TOMOYO_ID_DOMAIN,
@@ -370,9 +388,32 @@ struct tomoyo_number_group {
	struct tomoyo_number_union number;
};

/* Structure for entries which follows "struct tomoyo_condition". */
struct tomoyo_condition_element {
	/* Left hand operand. */
	u8 left;
	/* Right hand operand. */
	u8 right;
	/* Equation operator. True if equals or overlaps, false otherwise. */
	bool equals;
};

/* Structure for optional arguments. */
struct tomoyo_condition {
	struct tomoyo_shared_acl_head head;
	u32 size; /* Memory size allocated for this entry. */
	u16 condc; /* Number of conditions in this struct. */
	u16 numbers_count; /* Number of "struct tomoyo_number_union values". */
	/*
	 * struct tomoyo_condition_element condition[condc];
	 * struct tomoyo_number_union values[numbers_count];
	 */
};

/* Common header for individual entries. */
struct tomoyo_acl_info {
	struct list_head list;
	struct tomoyo_condition *cond; /* Maybe NULL. */
	bool is_deleted;
	u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */
} __packed;
@@ -475,12 +516,15 @@ struct tomoyo_io_buffer {
		unsigned int step;
		unsigned int query_index;
		u16 index;
		u16 cond_index;
		u8 acl_group_index;
		u8 cond_step;
		u8 bit;
		u8 w_pos;
		bool eof;
		bool print_this_domain_only;
		bool print_transition_related_only;
		bool print_cond_part;
		const char *w[TOMOYO_MAX_IO_READ_QUEUE];
	} r;
	struct {
@@ -586,6 +630,8 @@ struct tomoyo_policy_namespace {

bool tomoyo_compare_number_union(const unsigned long value,
				 const struct tomoyo_number_union *ptr);
bool tomoyo_condition(struct tomoyo_request_info *r,
		      const struct tomoyo_condition *cond);
bool tomoyo_correct_domain(const unsigned char *domainname);
bool tomoyo_correct_path(const char *filename);
bool tomoyo_correct_word(const char *string);
@@ -664,6 +710,7 @@ ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
			    const int buffer_len);
ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
			     const char __user *buffer, const int buffer_len);
struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param);
struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
						const bool transit);
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
@@ -675,6 +722,7 @@ struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
				      const u8 profile);
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
				const u8 index);
u8 tomoyo_parse_ulong(unsigned long *result, char **str);
void *tomoyo_commit_ok(void *data, const unsigned int size);
void __init tomoyo_load_builtin_policy(void);
void __init tomoyo_mm_init(void);
@@ -683,6 +731,7 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
					   const struct tomoyo_acl_info *));
void tomoyo_check_profile(void);
void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp);
void tomoyo_del_condition(struct list_head *element);
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns);
void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
@@ -706,6 +755,8 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
/********** External variable definitions. **********/

extern bool tomoyo_policy_loaded;
extern const char * const tomoyo_condition_keyword
[TOMOYO_MAX_CONDITION_KEYWORD];
extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
					      + TOMOYO_MAX_MAC_CATEGORY_INDEX];
@@ -715,6 +766,7 @@ extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX];
extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION];
extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION];
extern const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION];
extern struct list_head tomoyo_condition_list;
extern struct list_head tomoyo_domain_list;
extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
extern struct list_head tomoyo_namespace_list;
@@ -749,6 +801,36 @@ static inline void tomoyo_read_unlock(int idx)
	srcu_read_unlock(&tomoyo_ss, idx);
}

/**
 * tomoyo_sys_getppid - Copy of getppid().
 *
 * Returns parent process's PID.
 *
 * Alpha does not have getppid() defined. To be able to build this module on
 * Alpha, I have to copy getppid() from kernel/timer.c.
 */
static inline pid_t tomoyo_sys_getppid(void)
{
	pid_t pid;
	rcu_read_lock();
	pid = task_tgid_vnr(current->real_parent);
	rcu_read_unlock();
	return pid;
}

/**
 * tomoyo_sys_getpid - Copy of getpid().
 *
 * Returns current thread's PID.
 *
 * Alpha does not have getpid() defined. To be able to build this module on
 * Alpha, I have to copy getpid() from kernel/timer.c.
 */
static inline pid_t tomoyo_sys_getpid(void)
{
	return task_tgid_vnr(current);
}

/**
 * tomoyo_pathcmp - strcmp() for "struct tomoyo_path_info" structure.
 *
@@ -779,6 +861,19 @@ static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
	}
}

/**
 * tomoyo_put_condition - Drop reference on "struct tomoyo_condition".
 *
 * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
 *
 * Returns nothing.
 */
static inline void tomoyo_put_condition(struct tomoyo_condition *cond)
{
	if (cond)
		atomic_dec(&cond->head.users);
}

/**
 * tomoyo_put_group - Drop reference on "struct tomoyo_group".
 *
+349 −0
Original line number Diff line number Diff line
/*
 * security/tomoyo/condition.c
 *
 * Copyright (C) 2005-2011  NTT DATA CORPORATION
 */

#include "common.h"
#include <linux/slab.h>

/* List of "struct tomoyo_condition". */
LIST_HEAD(tomoyo_condition_list);

/**
 * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
 *
 * @a: Pointer to "struct tomoyo_condition".
 * @b: Pointer to "struct tomoyo_condition".
 *
 * Returns true if @a == @b, false otherwise.
 */
static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
					 const struct tomoyo_condition *b)
{
	return a->size == b->size && a->condc == b->condc &&
		a->numbers_count == b->numbers_count &&
		!memcmp(a + 1, b + 1, a->size - sizeof(*a));
}

/**
 * tomoyo_condition_type - Get condition type.
 *
 * @word: Keyword string.
 *
 * Returns one of values in "enum tomoyo_conditions_index" on success,
 * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
 */
static u8 tomoyo_condition_type(const char *word)
{
	u8 i;
	for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
		if (!strcmp(word, tomoyo_condition_keyword[i]))
			break;
	}
	return i;
}

/* Define this to enable debug mode. */
/* #define DEBUG_CONDITION */

#ifdef DEBUG_CONDITION
#define dprintk printk
#else
#define dprintk(...) do { } while (0)
#endif

/**
 * tomoyo_commit_condition - Commit "struct tomoyo_condition".
 *
 * @entry: Pointer to "struct tomoyo_condition".
 *
 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
 *
 * This function merges duplicated entries. This function returns NULL if
 * @entry is not duplicated but memory quota for policy has exceeded.
 */
static struct tomoyo_condition *tomoyo_commit_condition
(struct tomoyo_condition *entry)
{
	struct tomoyo_condition *ptr;
	bool found = false;
	if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
		dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
		ptr = NULL;
		found = true;
		goto out;
	}
	list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) {
		if (!tomoyo_same_condition(ptr, entry))
			continue;
		/* Same entry found. Share this entry. */
		atomic_inc(&ptr->head.users);
		found = true;
		break;
	}
	if (!found) {
		if (tomoyo_memory_ok(entry)) {
			atomic_set(&entry->head.users, 1);
			list_add_rcu(&entry->head.list,
				     &tomoyo_condition_list);
		} else {
			found = true;
			ptr = NULL;
		}
	}
	mutex_unlock(&tomoyo_policy_lock);
out:
	if (found) {
		tomoyo_del_condition(&entry->head.list);
		kfree(entry);
		entry = ptr;
	}
	return entry;
}

/**
 * tomoyo_get_condition - Parse condition part.
 *
 * @param: Pointer to "struct tomoyo_acl_param".
 *
 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
 */
struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
{
	struct tomoyo_condition *entry = NULL;
	struct tomoyo_condition_element *condp = NULL;
	struct tomoyo_number_union *numbers_p = NULL;
	struct tomoyo_condition e = { };
	char * const start_of_string = param->data;
	char * const end_of_string = start_of_string + strlen(start_of_string);
	char *pos;
rerun:
	pos = start_of_string;
	while (1) {
		u8 left = -1;
		u8 right = -1;
		char *left_word = pos;
		char *cp;
		char *right_word;
		bool is_not;
		if (!*left_word)
			break;
		/*
		 * Since left-hand condition does not allow use of "path_group"
		 * or "number_group" and environment variable's names do not
		 * accept '=', it is guaranteed that the original line consists
		 * of one or more repetition of $left$operator$right blocks
		 * where "$left is free from '=' and ' '" and "$operator is
		 * either '=' or '!='" and "$right is free from ' '".
		 * Therefore, we can reconstruct the original line at the end
		 * of dry run even if we overwrite $operator with '\0'.
		 */
		cp = strchr(pos, ' ');
		if (cp) {
			*cp = '\0'; /* Will restore later. */
			pos = cp + 1;
		} else {
			pos = "";
		}
		right_word = strchr(left_word, '=');
		if (!right_word || right_word == left_word)
			goto out;
		is_not = *(right_word - 1) == '!';
		if (is_not)
			*(right_word++ - 1) = '\0'; /* Will restore later. */
		else if (*(right_word + 1) != '=')
			*right_word++ = '\0'; /* Will restore later. */
		else
			goto out;
		dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
			is_not ? "!" : "", right_word);
		left = tomoyo_condition_type(left_word);
		dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
			left);
		if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
			if (!numbers_p) {
				e.numbers_count++;
			} else {
				e.numbers_count--;
				left = TOMOYO_NUMBER_UNION;
				param->data = left_word;
				if (*left_word == '@' ||
				    !tomoyo_parse_number_union(param,
							       numbers_p++))
					goto out;
			}
		}
		if (!condp)
			e.condc++;
		else
			e.condc--;
		right = tomoyo_condition_type(right_word);
		if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
			if (!numbers_p) {
				e.numbers_count++;
			} else {
				e.numbers_count--;
				right = TOMOYO_NUMBER_UNION;
				param->data = right_word;
				if (!tomoyo_parse_number_union(param,
							       numbers_p++))
					goto out;
			}
		}
		if (!condp) {
			dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
				"match=%u\n", __LINE__, left, right, !is_not);
			continue;
		}
		condp->left = left;
		condp->right = right;
		condp->equals = !is_not;
		dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
			__LINE__, condp->left, condp->right,
			condp->equals);
		condp++;
	}
	dprintk(KERN_INFO "%u: cond=%u numbers=%u\n",
		__LINE__, e.condc, e.numbers_count);
	if (entry) {
		BUG_ON(e.numbers_count | e.condc);
		return tomoyo_commit_condition(entry);
	}
	e.size = sizeof(*entry)
		+ e.condc * sizeof(struct tomoyo_condition_element)
		+ e.numbers_count * sizeof(struct tomoyo_number_union);
	entry = kzalloc(e.size, GFP_NOFS);
	if (!entry)
		return NULL;
	*entry = e;
	condp = (struct tomoyo_condition_element *) (entry + 1);
	numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
	{
		bool flag = false;
		for (pos = start_of_string; pos < end_of_string; pos++) {
			if (*pos)
				continue;
			if (flag) /* Restore " ". */
				*pos = ' ';
			else if (*(pos + 1) == '=') /* Restore "!=". */
				*pos = '!';
			else /* Restore "=". */
				*pos = '=';
			flag = !flag;
		}
	}
	goto rerun;
out:
	dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
	if (entry) {
		tomoyo_del_condition(&entry->head.list);
		kfree(entry);
	}
	return NULL;
}

/**
 * tomoyo_condition - Check condition part.
 *
 * @r:    Pointer to "struct tomoyo_request_info".
 * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
 *
 * Returns true on success, false otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
bool tomoyo_condition(struct tomoyo_request_info *r,
		      const struct tomoyo_condition *cond)
{
	u32 i;
	unsigned long min_v[2] = { 0, 0 };
	unsigned long max_v[2] = { 0, 0 };
	const struct tomoyo_condition_element *condp;
	const struct tomoyo_number_union *numbers_p;
	u16 condc;
	if (!cond)
		return true;
	condc = cond->condc;
	condp = (struct tomoyo_condition_element *) (cond + 1);
	numbers_p = (const struct tomoyo_number_union *) (condp + condc);
	for (i = 0; i < condc; i++) {
		const bool match = condp->equals;
		const u8 left = condp->left;
		const u8 right = condp->right;
		u8 j;
		condp++;
		/* Check numeric or bit-op expressions. */
		for (j = 0; j < 2; j++) {
			const u8 index = j ? right : left;
			unsigned long value = 0;
			switch (index) {
			case TOMOYO_TASK_UID:
				value = current_uid();
				break;
			case TOMOYO_TASK_EUID:
				value = current_euid();
				break;
			case TOMOYO_TASK_SUID:
				value = current_suid();
				break;
			case TOMOYO_TASK_FSUID:
				value = current_fsuid();
				break;
			case TOMOYO_TASK_GID:
				value = current_gid();
				break;
			case TOMOYO_TASK_EGID:
				value = current_egid();
				break;
			case TOMOYO_TASK_SGID:
				value = current_sgid();
				break;
			case TOMOYO_TASK_FSGID:
				value = current_fsgid();
				break;
			case TOMOYO_TASK_PID:
				value = tomoyo_sys_getpid();
				break;
			case TOMOYO_TASK_PPID:
				value = tomoyo_sys_getppid();
				break;
			case TOMOYO_NUMBER_UNION:
				/* Fetch values later. */
				break;
			default:
				break;
			}
			max_v[j] = value;
			min_v[j] = value;
		}
		if (left == TOMOYO_NUMBER_UNION) {
			/* Fetch values now. */
			const struct tomoyo_number_union *ptr = numbers_p++;
			min_v[0] = ptr->values[0];
			max_v[0] = ptr->values[1];
		}
		if (right == TOMOYO_NUMBER_UNION) {
			/* Fetch values now. */
			const struct tomoyo_number_union *ptr = numbers_p++;
			if (ptr->group) {
				if (tomoyo_number_matches_group(min_v[0],
								max_v[0],
								ptr->group)
				    == match)
					continue;
			} else {
				if ((min_v[0] <= ptr->values[1] &&
				     max_v[0] >= ptr->values[0]) == match)
					continue;
			}
			goto out;
		}
		/* Normal value range comparison. */
		if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
			continue;
out:
		return false;
	}
	return true;
}
Loading