[PATCH 1/4] TOMOYO: Add caller task's credential condition support.

From: Tetsuo Handa
Date: Thu Jun 10 2010 - 08:08:58 EST


This patch allows users to check caller task's UID/GID etc. for each request.
For example,

allow_read /tmp/file if task.uid=0

will allow opening /tmp/file for reading only if the caller task's UID is 0.

Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
---
security/tomoyo/Makefile | 2
security/tomoyo/common.c | 199 ++++++++++++++++++++----
security/tomoyo/common.h | 98 +++++++++++
security/tomoyo/condition.c | 364 ++++++++++++++++++++++++++++++++++++++++++++
security/tomoyo/domain.c | 17 +-
security/tomoyo/file.c | 62 +++++--
security/tomoyo/gc.c | 43 +++++
security/tomoyo/memory.c | 4
security/tomoyo/mount.c | 13 +
9 files changed, 733 insertions(+), 69 deletions(-)

--- security-testing-2.6.orig/security/tomoyo/Makefile
+++ security-testing-2.6/security/tomoyo/Makefile
@@ -1 +1 @@
-obj-y = common.o domain.o file.o gc.o load_policy.o memory.o mount.o number_group.o path_group.o realpath.o securityfs_if.o tomoyo.o util.o
+obj-y = condition.o common.o domain.o file.o gc.o load_policy.o memory.o mount.o number_group.o path_group.o realpath.o securityfs_if.o tomoyo.o util.o
--- security-testing-2.6.orig/security/tomoyo/common.c
+++ security-testing-2.6/security/tomoyo/common.c
@@ -85,7 +85,7 @@ static const char *tomoyo_yesno(const un
* Returns true on success, false otherwise.
*/
static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head,
- const struct tomoyo_name_union *ptr)
+ const struct tomoyo_name_union *ptr)
{
int pos = head->read_avail;
if (pos && head->read_buf[pos - 1] == ' ')
@@ -97,25 +97,27 @@ static bool tomoyo_print_name_union(stru
}

/**
- * tomoyo_print_number_union - Print a tomoyo_number_union.
+ * tomoyo_print_number_union_common - Print a tomoyo_number_union.
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @ptr: Pointer to "struct tomoyo_number_union".
+ * @need_space: True if a space character is needed.
*
* Returns true on success, false otherwise.
*/
-bool tomoyo_print_number_union(struct tomoyo_io_buffer *head,
- const struct tomoyo_number_union *ptr)
+static bool tomoyo_print_number_union_common(struct tomoyo_io_buffer *head,
+ const struct tomoyo_number_union *ptr,
+ const bool need_space)
{
unsigned long min;
unsigned long max;
u8 min_type;
u8 max_type;
- if (!tomoyo_io_printf(head, " "))
+ if (need_space && !tomoyo_io_printf(head, " "))
return false;
if (ptr->is_group)
return tomoyo_io_printf(head, "@%s",
- ptr->group->group_name->name);
+ ptr->group->group_name->name);
min_type = ptr->min_type;
max_type = ptr->max_type;
min = ptr->values[0];
@@ -147,6 +149,35 @@ bool tomoyo_print_number_union(struct to
}

/**
+ * tomoyo_print_number_union - Print a tomoyo_number_union.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_print_number_union(struct tomoyo_io_buffer *head,
+ const struct tomoyo_number_union *ptr)
+{
+ return tomoyo_print_number_union_common(head, ptr, true);
+}
+
+/**
+ * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space character.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_number_union_nospace(struct tomoyo_io_buffer *head,
+ const struct tomoyo_number_union
+ *ptr)
+{
+ return tomoyo_print_number_union_common(head, ptr, false);
+}
+
+/**
* tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -729,11 +760,39 @@ static int tomoyo_delete_domain(char *do
*/
static int tomoyo_write_domain_policy2(char *data,
struct tomoyo_domain_info *domain,
+ struct tomoyo_condition *cond,
const bool is_delete)
{
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT))
- return tomoyo_write_mount_policy(data, domain, is_delete);
- return tomoyo_write_file_policy(data, domain, is_delete);
+ return tomoyo_write_mount_policy(data, domain, cond, is_delete);
+ return tomoyo_write_file_policy(data, domain, cond, is_delete);
+}
+
+/**
+ * tomoyo_find_condition_part - Find condition part from the statement.
+ *
+ * @data: String to parse.
+ *
+ * Returns pointer to the condition part if it was found in the statement,
+ * NULL otherwise.
+ */
+static char *tomoyo_find_condition_part(char *data)
+{
+ char *cp = strstr(data, " if ");
+ if (cp) {
+ while (1) {
+ char *cp2 = strstr(cp + 3, " if ");
+ if (!cp2)
+ break;
+ cp = cp2;
+ }
+ *cp++ = '\0';
+ } else {
+ cp = strstr(data, " ; set ");
+ if (cp)
+ *cp++ = '\0';
+ }
+ return cp;
}

/**
@@ -752,6 +811,9 @@ static int tomoyo_write_domain_policy(st
bool is_delete = false;
bool is_select = false;
unsigned int profile;
+ struct tomoyo_condition *cond = NULL;
+ char *cp;
+ int error;

if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE))
is_delete = true;
@@ -794,7 +856,82 @@ static int tomoyo_write_domain_policy(st
domain->transition_failed = !is_delete;
return 0;
}
- return tomoyo_write_domain_policy2(data, domain, is_delete);
+ cp = tomoyo_find_condition_part(data);
+ if (cp) {
+ cond = tomoyo_get_condition(cp);
+ if (!cond)
+ return -EINVAL;
+ }
+ error = tomoyo_write_domain_policy2(data, domain, cond, is_delete);
+ if (cond)
+ tomoyo_put_condition(cond);
+ return error;
+}
+
+/**
+ * tomoyo_print_condition - Print condition part.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @cond: Pointer to "struct tomoyo_condition". May be NULL.
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
+ const struct tomoyo_condition *cond)
+{
+ const struct tomoyo_condition_element *condp;
+ const struct tomoyo_number_union *numbers_p;
+ u16 condc;
+ u16 i;
+ char buffer[32];
+ if (!cond)
+ goto no_condition;
+ condc = cond->condc;
+ condp = (const struct tomoyo_condition_element *) (cond + 1);
+ numbers_p = (const struct tomoyo_number_union *) (condp + condc);
+ memset(buffer, 0, sizeof(buffer));
+ if (condc && !tomoyo_io_printf(head, "%s", " if"))
+ goto out;
+ for (i = 0; i < condc; i++) {
+ const u8 match = condp->equals;
+ const u8 left = condp->left;
+ const u8 right = condp->right;
+ condp++;
+ switch (left) {
+ case TOMOYO_NUMBER_UNION:
+ if (!tomoyo_print_number_union(head, numbers_p++))
+ goto out;
+ break;
+ default:
+ if (left >= TOMOYO_MAX_CONDITION_KEYWORD)
+ goto out;
+ if (!tomoyo_io_printf(head, " %s",
+ tomoyo_condition_keyword[left]))
+ goto out;
+ break;
+ }
+ if (!tomoyo_io_printf(head, "%s", match ? "=" : "!="))
+ goto out;
+ switch (right) {
+ case TOMOYO_NUMBER_UNION:
+ if (!tomoyo_print_number_union_nospace(head,
+ numbers_p++))
+ goto out;
+ break;
+ default:
+ if (right >= TOMOYO_MAX_CONDITION_KEYWORD)
+ goto out;
+ if (!tomoyo_io_printf(head, "%s",
+ tomoyo_condition_keyword[right]))
+ goto out;
+ break;
+ }
+ }
+ no_condition:
+ if (tomoyo_io_printf(head, "\n"))
+ return true;
+ out:
+ return false;
}

/**
@@ -802,11 +939,13 @@ static int tomoyo_write_domain_policy(st
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @ptr: Pointer to "struct tomoyo_path_acl".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
*
* Returns true on success, false otherwise.
*/
static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head,
- struct tomoyo_path_acl *ptr)
+ struct tomoyo_path_acl *ptr,
+ const struct tomoyo_condition *cond)
{
int pos;
u8 bit;
@@ -823,7 +962,7 @@ static bool tomoyo_print_path_acl(struct
if (!tomoyo_io_printf(head, "allow_%s ",
tomoyo_path2keyword(bit)) ||
!tomoyo_print_name_union(head, &ptr->name) ||
- !tomoyo_io_printf(head, "\n"))
+ !tomoyo_print_condition(head, cond))
goto out;
}
head->read_bit = 0;
@@ -839,11 +978,13 @@ static bool tomoyo_print_path_acl(struct
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @ptr: Pointer to "struct tomoyo_path2_acl".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
*
* Returns true on success, false otherwise.
*/
static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head,
- struct tomoyo_path2_acl *ptr)
+ struct tomoyo_path2_acl *ptr,
+ const struct tomoyo_condition *cond)
{
int pos;
const u8 perm = ptr->perm;
@@ -857,7 +998,7 @@ static bool tomoyo_print_path2_acl(struc
tomoyo_path22keyword(bit)) ||
!tomoyo_print_name_union(head, &ptr->name1) ||
!tomoyo_print_name_union(head, &ptr->name2) ||
- !tomoyo_io_printf(head, "\n"))
+ !tomoyo_print_condition(head, cond))
goto out;
}
head->read_bit = 0;
@@ -873,11 +1014,13 @@ static bool tomoyo_print_path2_acl(struc
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @ptr: Pointer to "struct tomoyo_path_number_acl".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
*
* Returns true on success, false otherwise.
*/
static bool tomoyo_print_path_number_acl(struct tomoyo_io_buffer *head,
- struct tomoyo_path_number_acl *ptr)
+ struct tomoyo_path_number_acl *ptr,
+ const struct tomoyo_condition *cond)
{
int pos;
u8 bit;
@@ -891,7 +1034,7 @@ static bool tomoyo_print_path_number_acl
tomoyo_path_number2keyword(bit)) ||
!tomoyo_print_name_union(head, &ptr->name) ||
!tomoyo_print_number_union(head, &ptr->number) ||
- !tomoyo_io_printf(head, "\n"))
+ !tomoyo_print_condition(head, cond))
goto out;
}
head->read_bit = 0;
@@ -907,11 +1050,13 @@ static bool tomoyo_print_path_number_acl
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @ptr: Pointer to "struct tomoyo_path_number3_acl".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
*
* Returns true on success, false otherwise.
*/
static bool tomoyo_print_path_number3_acl(struct tomoyo_io_buffer *head,
- struct tomoyo_path_number3_acl *ptr)
+ struct tomoyo_path_number3_acl *ptr,
+ const struct tomoyo_condition *cond)
{
int pos;
u8 bit;
@@ -927,7 +1072,7 @@ static bool tomoyo_print_path_number3_ac
!tomoyo_print_number_union(head, &ptr->mode) ||
!tomoyo_print_number_union(head, &ptr->major) ||
!tomoyo_print_number_union(head, &ptr->minor) ||
- !tomoyo_io_printf(head, "\n"))
+ !tomoyo_print_condition(head, cond))
goto out;
}
head->read_bit = 0;
@@ -943,11 +1088,13 @@ static bool tomoyo_print_path_number3_ac
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @ptr: Pointer to "struct tomoyo_mount_acl".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
*
* Returns true on success, false otherwise.
*/
static bool tomoyo_print_mount_acl(struct tomoyo_io_buffer *head,
- struct tomoyo_mount_acl *ptr)
+ struct tomoyo_mount_acl *ptr,
+ const struct tomoyo_condition *cond)
{
const int pos = head->read_avail;
if (ptr->is_deleted)
@@ -957,7 +1104,7 @@ static bool tomoyo_print_mount_acl(struc
!tomoyo_print_name_union(head, &ptr->dir_name) ||
!tomoyo_print_name_union(head, &ptr->fs_type) ||
!tomoyo_print_number_union(head, &ptr->flags) ||
- !tomoyo_io_printf(head, "\n")) {
+ !tomoyo_print_condition(head, cond)) {
head->read_avail = pos;
return false;
}
@@ -975,34 +1122,35 @@ static bool tomoyo_print_mount_acl(struc
static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
struct tomoyo_acl_info *ptr)
{
+ const struct tomoyo_condition *cond = ptr->cond;
const u8 acl_type = ptr->type;

if (acl_type == TOMOYO_TYPE_PATH_ACL) {
struct tomoyo_path_acl *acl
= container_of(ptr, struct tomoyo_path_acl, head);
- return tomoyo_print_path_acl(head, acl);
+ return tomoyo_print_path_acl(head, acl, cond);
}
if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
struct tomoyo_path2_acl *acl
= container_of(ptr, struct tomoyo_path2_acl, head);
- return tomoyo_print_path2_acl(head, acl);
+ return tomoyo_print_path2_acl(head, acl, cond);
}
if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
struct tomoyo_path_number_acl *acl
= container_of(ptr, struct tomoyo_path_number_acl,
head);
- return tomoyo_print_path_number_acl(head, acl);
+ return tomoyo_print_path_number_acl(head, acl, cond);
}
if (acl_type == TOMOYO_TYPE_PATH_NUMBER3_ACL) {
struct tomoyo_path_number3_acl *acl
= container_of(ptr, struct tomoyo_path_number3_acl,
head);
- return tomoyo_print_path_number3_acl(head, acl);
+ return tomoyo_print_path_number3_acl(head, acl, cond);
}
if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
struct tomoyo_mount_acl *acl
= container_of(ptr, struct tomoyo_mount_acl, head);
- return tomoyo_print_mount_acl(head, acl);
+ return tomoyo_print_mount_acl(head, acl, cond);
}
BUG(); /* This must not happen. */
return false;
@@ -1445,8 +1593,7 @@ int tomoyo_supervisor(struct tomoyo_requ
vsnprintf(buffer, len - 1, fmt, args);
va_end(args);
tomoyo_normalize_line(buffer);
- tomoyo_write_domain_policy2(buffer, r->domain, false);
- kfree(buffer);
+ tomoyo_write_domain_policy2(buffer, r->domain, NULL, false);
/* fall through */
case TOMOYO_CONFIG_PERMISSIVE:
return 0;
--- security-testing-2.6.orig/security/tomoyo/common.h
+++ security-testing-2.6/security/tomoyo/common.h
@@ -21,7 +21,7 @@
#include <linux/list.h>
#include <linux/cred.h>
#include <linux/poll.h>
-struct linux_binprm;
+#include <linux/binfmts.h>

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

@@ -182,20 +182,65 @@ enum tomoyo_mac_category_index {
TOMOYO_MAX_MAC_CATEGORY_INDEX
};

+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,
+};
+
#define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */

/********** Structure definitions. **********/

+struct tomoyo_condition_element {
+ /* Left hand operand. */
+ u8 left;
+ /*
+ * Right hand operand. A "struct tomoyo_number_union" for
+ * TOMOYO_NUMBER_UNION is attached to the tail of the array of this
+ * struct.
+ */
+ u8 right;
+ /* Equation operator. true if equals or overlaps, false otherwise. */
+ bool equals;
+};
+
+/* Structure for " if " part. */
+struct tomoyo_condition {
+ struct list_head list;
+ atomic_t users;
+ u32 size;
+ u16 condc;
+ u16 numbers_count;
+ /*
+ * struct tomoyo_condition_element condition[condc];
+ * struct tomoyo_number_union values[numbers_count];
+ */
+};
+
+struct tomoyo_execve_entry;
+
/*
* tomoyo_request_info is a structure which is used for holding
*
* (1) Domain information of current process.
- * (2) How many retries are made for this request.
- * (3) Profile number used for this request.
- * (4) Access control mode of the profile.
+ * (2) Parameters specific to execve() request. NULL if not for execve().
+ * (3) How many retries are made for this request.
+ * (4) Profile number used for this request.
+ * (5) Access control mode of the profile.
*/
struct tomoyo_request_info {
struct tomoyo_domain_info *domain;
+ struct tomoyo_execve_entry *ee;
u8 retry;
u8 profile;
u8 mode; /* One of tomoyo_mode_index . */
@@ -284,12 +329,21 @@ struct tomoyo_number_group_member {
struct tomoyo_number_union number;
};

+/* Structure for execve() operation. */
+struct tomoyo_execve_entry {
+ struct tomoyo_request_info r;
+ int reader_idx;
+ /* For temporary use. */
+ char *tmp; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
+};
+
/*
* tomoyo_acl_info is a structure which is used for holding
*
* (1) "list" which is linked to the ->acl_info_list of
* "struct tomoyo_domain_info"
- * (2) "type" which tells type of the entry (either
+ * (2) "cond" which tells optional conditions for this entry. Maybe NULL.
+ * (3) "type" which tells type of the entry (either
* "struct tomoyo_path_acl" or "struct tomoyo_path2_acl").
*
* Packing "struct tomoyo_acl_info" allows
@@ -299,6 +353,7 @@ struct tomoyo_number_group_member {
*/
struct tomoyo_acl_info {
struct list_head list;
+ struct tomoyo_condition *cond;
u8 type;
} __packed;

@@ -697,6 +752,11 @@ struct tomoyo_profile {
extern asmlinkage long sys_getpid(void);
extern asmlinkage long sys_getppid(void);

+bool tomoyo_condition(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *acl);
+u8 tomoyo_parse_ulong(unsigned long *result, char **str);
+struct tomoyo_condition *tomoyo_get_condition(char * const condition);
+void tomoyo_del_condition(struct tomoyo_condition *cond);
/* Check whether the given string starts with the given keyword. */
bool tomoyo_str_starts(char **src, const char *find);
/* Get tomoyo_realpath() of current process. */
@@ -817,11 +877,13 @@ int tomoyo_write_domain_keeper_policy(ch
* "allow_link" entry in domain policy.
*/
int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
+ struct tomoyo_condition *cond,
const bool is_delete);
/* Create "allow_read" entry in exception policy. */
int tomoyo_write_globally_readable_policy(char *data, const bool is_delete);
/* Create "allow_mount" entry in domain policy. */
int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain,
+ struct tomoyo_condition *cond,
const bool is_delete);
/* Create "deny_rewrite" entry in exception policy. */
int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete);
@@ -932,6 +994,7 @@ extern struct list_head tomoyo_globally_
extern struct list_head tomoyo_pattern_list;
extern struct list_head tomoyo_no_rewrite_list;
extern struct list_head tomoyo_policy_manager_list;
+extern struct list_head tomoyo_condition_list;
extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];

/* Lock for protecting policy. */
@@ -943,6 +1006,7 @@ extern bool tomoyo_policy_loaded;
/* The kernel's domain. */
extern struct tomoyo_domain_info tomoyo_kernel_domain;

+extern const char *tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD];
extern unsigned int tomoyo_quota_for_query;
extern unsigned int tomoyo_query_memory_size;

@@ -989,6 +1053,12 @@ static inline bool tomoyo_is_invalid(con
return c && (c <= ' ' || c >= 127);
}

+static inline void tomoyo_put_condition(struct tomoyo_condition *cond)
+{
+ if (cond)
+ atomic_dec(&cond->users);
+}
+
static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
{
if (name) {
@@ -1010,6 +1080,14 @@ static inline void tomoyo_put_number_gro
atomic_dec(&group->users);
}

+static inline void tomoyo_add_domain_acl(struct tomoyo_domain_info *domain,
+ struct tomoyo_acl_info *acl)
+{
+ if (acl->cond)
+ atomic_inc(&acl->cond->users);
+ list_add_tail_rcu(&acl->list, &domain->acl_info_list);
+}
+
static inline struct tomoyo_domain_info *tomoyo_domain(void)
{
return current_cred()->security;
@@ -1024,7 +1102,7 @@ static inline struct tomoyo_domain_info
static inline bool tomoyo_is_same_acl_head(const struct tomoyo_acl_info *p1,
const struct tomoyo_acl_info *p2)
{
- return p1->type == p2->type;
+ return p1->type == p2->type && p1->cond == p2->cond;
}

static inline bool tomoyo_is_same_name_union
@@ -1114,6 +1192,14 @@ static inline bool tomoyo_is_same_aggreg
p1->aggregated_name == p2->aggregated_name;
}

+static inline bool tomoyo_is_same_condition(const struct tomoyo_condition *p1,
+ const struct tomoyo_condition *p2)
+{
+ return p1->size == p2->size && p1->condc == p2->condc &&
+ p1->numbers_count == p2->numbers_count &&
+ !memcmp(p1 + 1, p2 + 1, p1->size - sizeof(*p1));
+}
+
static inline bool tomoyo_is_same_alias_entry
(const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2)
{
--- /dev/null
+++ security-testing-2.6/security/tomoyo/condition.c
@@ -0,0 +1,364 @@
+/*
+ * security/tomoyo/condition.c
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/slab.h>
+
+/* The list for "struct tomoyo_condition". */
+LIST_HEAD(tomoyo_condition_list);
+
+const char *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",
+};
+
+/* #define DEBUG_CONDITION */
+
+#ifdef DEBUG_CONDITION
+#define dprintk printk
+#else
+#define dprintk(...) do { } while (0)
+#endif
+
+/**
+ * tomoyo_get_condition - Parse condition part.
+ *
+ * @condition: Pointer to string to parse.
+ *
+ * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
+ */
+struct tomoyo_condition *tomoyo_get_condition(char * const condition)
+{
+ char *start = condition;
+ struct tomoyo_condition *entry = NULL;
+ struct tomoyo_condition *ptr;
+ struct tomoyo_condition_element *condp;
+ struct tomoyo_number_union *numbers_p;
+ u32 size;
+ bool found = false;
+ u16 condc = 0;
+ u16 numbers_count = 0;
+ char *end_of_string;
+ start = condition;
+ if (!strncmp(start, "if ", 3))
+ start += 3;
+ else if (*start)
+ return NULL;
+ end_of_string = start + strlen(start);
+ while (1) {
+ u8 left;
+ u8 right;
+ char *word = start;
+ char *cp;
+ char *eq;
+ bool is_not = false;
+ if (!*word)
+ break;
+ cp = strchr(start, ' ');
+ if (cp) {
+ *cp = '\0';
+ start = cp + 1;
+ } else {
+ start = "";
+ }
+ dprintk(KERN_WARNING "%u: <%s>\n", __LINE__, word);
+ eq = strchr(word, '=');
+ if (!eq)
+ goto out;
+ if (eq > word && *(eq - 1) == '!') {
+ is_not = true;
+ eq--;
+ }
+ *eq = '\0';
+ for (left = 0; left < TOMOYO_MAX_CONDITION_KEYWORD; left++) {
+ if (strcmp(word, tomoyo_condition_keyword[left]))
+ continue;
+ break;
+ }
+ dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__,
+ word, left);
+ if (left == TOMOYO_MAX_CONDITION_KEYWORD)
+ numbers_count++;
+ *eq = is_not ? '!' : '=';
+ word = eq + 1;
+ if (is_not)
+ word++;
+ condc++;
+ dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__,
+ word, left);
+ for (right = 0; right < TOMOYO_MAX_CONDITION_KEYWORD; right++) {
+ if (strcmp(word, tomoyo_condition_keyword[right]))
+ continue;
+ break;
+ }
+ dprintk(KERN_WARNING "%u: <%s> right=%u\n", __LINE__,
+ word, right);
+ if (right == TOMOYO_MAX_CONDITION_KEYWORD)
+ numbers_count++;
+ }
+ dprintk(KERN_DEBUG "%u: cond=%u numbers=%u\n", __LINE__,
+ condc, numbers_count);
+ size = sizeof(*entry)
+ + condc * sizeof(struct tomoyo_condition_element)
+ + numbers_count * sizeof(struct tomoyo_number_union);
+ entry = kzalloc(size, GFP_NOFS);
+ if (!entry)
+ return NULL;
+ INIT_LIST_HEAD(&entry->list);
+ entry->condc = condc;
+ entry->numbers_count = numbers_count;
+ condp = (struct tomoyo_condition_element *) (entry + 1);
+ numbers_p = (struct tomoyo_number_union *) (condp + condc);
+ for (start = condition; start < end_of_string; start++)
+ if (!*start)
+ *start = ' ';
+ start = condition;
+ if (!strncmp(start, "if ", 3))
+ start += 3;
+ else if (*start)
+ goto out;
+ while (1) {
+ u8 left;
+ u8 right;
+ char *word = start;
+ char *cp;
+ char *eq;
+ bool is_not = false;
+ if (!*word)
+ break;
+ cp = strchr(start, ' ');
+ if (cp) {
+ *cp = '\0';
+ start = cp + 1;
+ } else {
+ start = "";
+ }
+ dprintk(KERN_WARNING "%u: <%s>\n", __LINE__, word);
+ eq = strchr(word, '=');
+ if (!eq) {
+ dprintk(KERN_WARNING "%u: No operator.\n",
+ __LINE__);
+ goto out;
+ }
+ if (eq > word && *(eq - 1) == '!') {
+ is_not = true;
+ eq--;
+ }
+ *eq = '\0';
+ for (left = 0; left < TOMOYO_MAX_CONDITION_KEYWORD; left++) {
+ if (strcmp(word, tomoyo_condition_keyword[left]))
+ continue;
+ break;
+ }
+ dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__,
+ word, left);
+ if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
+ left = TOMOYO_NUMBER_UNION;
+ if (!tomoyo_parse_number_union(word, numbers_p))
+ goto out;
+ if (numbers_p->is_group)
+ goto out;
+ numbers_p++;
+ numbers_count--;
+ }
+ *eq = is_not ? '!' : '=';
+ word = eq + 1;
+ if (is_not)
+ word++;
+ condc--;
+ dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__,
+ word, left);
+ for (right = 0; right < TOMOYO_MAX_CONDITION_KEYWORD; right++) {
+ if (strcmp(word, tomoyo_condition_keyword[right]))
+ continue;
+ break;
+ }
+ if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
+ right = TOMOYO_NUMBER_UNION;
+ if (!tomoyo_parse_number_union(word, numbers_p++))
+ goto out;
+ numbers_count--;
+ }
+ 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++;
+ }
+#ifdef DEBUG_CONFITION
+ for (start = condition; start < end_of_string; start++)
+ if (!*start)
+ *start = ' ';
+ dprintk(KERN_DEBUG "%u: <%s> cond=%u numbers=%u\n",
+ __LINE__, condition, condc, numbers_count);
+ BUG_ON(numbers_count);
+ BUG_ON(condc);
+#else
+ BUG_ON(numbers_count | condc);
+#endif
+ entry->size = size;
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ list_for_each_entry_rcu(ptr, &tomoyo_condition_list, list) {
+ if (!tomoyo_is_same_condition(ptr, entry))
+ continue;
+ /* Same entry found. Share this entry. */
+ atomic_inc(&ptr->users);
+ found = true;
+ break;
+ }
+ if (!found) {
+ if (tomoyo_memory_ok(entry)) {
+ atomic_set(&entry->users, 1);
+ list_add_rcu(&entry->list, &tomoyo_condition_list);
+ } else {
+ found = true;
+ ptr = NULL;
+ }
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ if (found) {
+ tomoyo_del_condition(entry);
+ kfree(entry);
+ entry = ptr;
+ }
+ return entry;
+ out:
+ dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
+ if (entry) {
+ tomoyo_del_condition(entry);
+ kfree(entry);
+ }
+ return NULL;
+}
+
+/**
+ * tomoyo_condition - Check condition part.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @acl: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_condition(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *acl)
+{
+ u32 i;
+ unsigned long left_min = 0;
+ unsigned long left_max = 0;
+ unsigned long right_min = 0;
+ unsigned long right_max = 0;
+ const struct tomoyo_condition_element *condp;
+ const struct tomoyo_number_union *numbers_p;
+ u16 condc;
+ const struct tomoyo_condition *cond = acl->cond;
+ 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 = sys_getpid();
+ break;
+ case TOMOYO_TASK_PPID:
+ value = sys_getppid();
+ break;
+ case TOMOYO_NUMBER_UNION:
+ /* Fetch values later. */
+ break;
+ default:
+ goto out;
+ }
+ value = value;
+ if (j) {
+ right_max = value;
+ right_min = value;
+ } else {
+ left_max = value;
+ left_min = value;
+ }
+ }
+ if (left == TOMOYO_NUMBER_UNION) {
+ /* Fetch values now. */
+ const struct tomoyo_number_union *ptr = numbers_p++;
+ left_min = ptr->values[0];
+ left_max = ptr->values[1];
+ }
+ if (right == TOMOYO_NUMBER_UNION) {
+ /* Fetch values now. */
+ const struct tomoyo_number_union *ptr = numbers_p++;
+ if (ptr->is_group) {
+ if (tomoyo_number_matches_group(left_min,
+ left_max,
+ ptr->group)
+ == match)
+ continue;
+ } else {
+ if ((left_min <= ptr->values[1] &&
+ left_max >= ptr->values[0]) == match)
+ continue;
+ }
+ goto out;
+ }
+ if (match) {
+ if (left_min <= right_max && left_max >= right_min)
+ continue;
+ } else {
+ if (left_min > right_max || left_max < right_min)
+ continue;
+ }
+ out:
+ return false;
+ }
+ return true;
+}
--- security-testing-2.6.orig/security/tomoyo/domain.c
+++ security-testing-2.6/security/tomoyo/domain.c
@@ -9,6 +9,7 @@
#include "common.h"
#include <linux/binfmts.h>
#include <linux/slab.h>
+#include <linux/highmem.h>

/* Variables definitions.*/

@@ -806,13 +807,12 @@ struct tomoyo_domain_info *tomoyo_find_o
*/
int tomoyo_find_next_domain(struct linux_binprm *bprm)
{
+ char *tmp = kmalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
struct tomoyo_request_info r;
- char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
struct tomoyo_domain_info *old_domain = tomoyo_domain();
struct tomoyo_domain_info *domain = NULL;
const char *old_domain_name = old_domain->domainname->name;
const char *original_name = bprm->filename;
- u8 mode;
bool is_enforce;
int retval = -ENOMEM;
bool need_kfree = false;
@@ -820,13 +820,13 @@ int tomoyo_find_next_domain(struct linux
struct tomoyo_path_info sn = { }; /* symlink name */
struct tomoyo_path_info ln; /* last name */

- ln.name = tomoyo_get_last_name(old_domain);
- tomoyo_fill_path_info(&ln);
- mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
- is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
if (!tmp)
- goto out;
+ return -ENOMEM;
+ tomoyo_init_request_info(&r, NULL, TOMOYO_TYPE_EXECUTE);
+ is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);

+ ln.name = tomoyo_get_last_name(old_domain);
+ tomoyo_fill_path_info(&ln);
retry:
if (need_kfree) {
kfree(rn.name);
@@ -924,7 +924,8 @@ int tomoyo_find_next_domain(struct linux
done:
if (domain)
goto out;
- printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
+ printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
+ tmp);
if (is_enforce)
retval = -EPERM;
else
--- security-testing-2.6.orig/security/tomoyo/file.c
+++ security-testing-2.6/security/tomoyo/file.c
@@ -221,9 +221,11 @@ static bool tomoyo_get_realpath(struct t
static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
const char *filename2,
struct tomoyo_domain_info *const domain,
+ struct tomoyo_condition *cond,
const bool is_delete);
static int tomoyo_update_path_acl(const u8 type, const char *filename,
struct tomoyo_domain_info *const domain,
+ struct tomoyo_condition *cond,
const bool is_delete);

/*
@@ -670,6 +672,7 @@ bool tomoyo_read_no_rewrite_policy(struc
* @perm: Permission (between 1 to 7).
* @filename: Filename.
* @domain: Pointer to "struct tomoyo_domain_info".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
@@ -683,6 +686,7 @@ bool tomoyo_read_no_rewrite_policy(struc
*/
static int tomoyo_update_file_acl(u8 perm, const char *filename,
struct tomoyo_domain_info * const domain,
+ struct tomoyo_condition *cond,
const bool is_delete)
{
if (perm > 7 || !perm) {
@@ -698,13 +702,13 @@ static int tomoyo_update_file_acl(u8 per
return 0;
if (perm & 4)
tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain,
- is_delete);
+ cond, is_delete);
if (perm & 2)
tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain,
- is_delete);
+ cond, is_delete);
if (perm & 1)
tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain,
- is_delete);
+ cond, is_delete);
return 0;
}

@@ -719,7 +723,7 @@ static int tomoyo_update_file_acl(u8 per
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_path_acl(const struct tomoyo_request_info *r,
+static int tomoyo_path_acl(struct tomoyo_request_info *r,
const struct tomoyo_path_info *filename,
const u32 perm)
{
@@ -733,7 +737,8 @@ static int tomoyo_path_acl(const struct
continue;
acl = container_of(ptr, struct tomoyo_path_acl, head);
if (!(acl->perm & perm) ||
- !tomoyo_compare_name_union(filename, &acl->name))
+ !tomoyo_compare_name_union(filename, &acl->name) ||
+ !tomoyo_condition(r, ptr))
continue;
error = 0;
break;
@@ -803,6 +808,7 @@ static int tomoyo_file_perm(struct tomoy
* @type: Type of operation.
* @filename: Filename.
* @domain: Pointer to "struct tomoyo_domain_info".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
@@ -811,6 +817,7 @@ static int tomoyo_file_perm(struct tomoy
*/
static int tomoyo_update_path_acl(const u8 type, const char *filename,
struct tomoyo_domain_info *const domain,
+ struct tomoyo_condition *cond,
const bool is_delete)
{
static const u16 tomoyo_rw_mask =
@@ -819,6 +826,7 @@ static int tomoyo_update_path_acl(const
struct tomoyo_acl_info *ptr;
struct tomoyo_path_acl e = {
.head.type = TOMOYO_TYPE_PATH_ACL,
+ .head.cond = cond,
.perm = perm
};
int error = is_delete ? -ENOENT : -ENOMEM;
@@ -856,8 +864,7 @@ static int tomoyo_update_path_acl(const
struct tomoyo_path_acl *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
- list_add_tail_rcu(&entry->head.list,
- &domain->acl_info_list);
+ tomoyo_add_domain_acl(domain, &entry->head);
error = 0;
}
}
@@ -876,6 +883,7 @@ static int tomoyo_update_path_acl(const
* @major: Device major number.
* @minor: Device minor number.
* @domain: Pointer to "struct tomoyo_domain_info".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
@@ -886,12 +894,14 @@ static inline int tomoyo_update_path_num
char *major, char *minor,
struct tomoyo_domain_info *
const domain,
+ struct tomoyo_condition *cond,
const bool is_delete)
{
const u8 perm = 1 << type;
struct tomoyo_acl_info *ptr;
struct tomoyo_path_number3_acl e = {
.head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL,
+ .head.cond = cond,
.perm = perm
};
int error = is_delete ? -ENOENT : -ENOMEM;
@@ -918,8 +928,7 @@ static inline int tomoyo_update_path_num
struct tomoyo_path_number3_acl *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
- list_add_tail_rcu(&entry->head.list,
- &domain->acl_info_list);
+ tomoyo_add_domain_acl(domain, &entry->head);
error = 0;
}
}
@@ -939,6 +948,7 @@ static inline int tomoyo_update_path_num
* @filename1: First filename.
* @filename2: Second filename.
* @domain: Pointer to "struct tomoyo_domain_info".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
@@ -948,11 +958,13 @@ static inline int tomoyo_update_path_num
static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
const char *filename2,
struct tomoyo_domain_info *const domain,
+ struct tomoyo_condition *cond,
const bool is_delete)
{
const u8 perm = 1 << type;
struct tomoyo_path2_acl e = {
.head.type = TOMOYO_TYPE_PATH2_ACL,
+ .head.cond = cond,
.perm = perm
};
struct tomoyo_acl_info *ptr;
@@ -981,8 +993,7 @@ static int tomoyo_update_path2_acl(const
struct tomoyo_path2_acl *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
- list_add_tail_rcu(&entry->head.list,
- &domain->acl_info_list);
+ tomoyo_add_domain_acl(domain, &entry->head);
error = 0;
}
}
@@ -1031,6 +1042,8 @@ static int tomoyo_path_number3_acl(struc
continue;
if (!tomoyo_compare_name_union(filename, &acl->name))
continue;
+ if (!tomoyo_condition(r, ptr))
+ continue;
error = 0;
break;
}
@@ -1049,7 +1062,7 @@ static int tomoyo_path_number3_acl(struc
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_path2_acl(const struct tomoyo_request_info *r, const u8 type,
+static int tomoyo_path2_acl(struct tomoyo_request_info *r, const u8 type,
const struct tomoyo_path_info *filename1,
const struct tomoyo_path_info *filename2)
{
@@ -1069,6 +1082,8 @@ static int tomoyo_path2_acl(const struct
continue;
if (!tomoyo_compare_name_union(filename2, &acl->name2))
continue;
+ if (!tomoyo_condition(r, ptr))
+ continue;
error = 0;
break;
}
@@ -1149,7 +1164,8 @@ static int tomoyo_path_number_acl(struct
head);
if (!(acl->perm & perm) ||
!tomoyo_compare_number_union(number, &acl->number) ||
- !tomoyo_compare_name_union(filename, &acl->name))
+ !tomoyo_compare_name_union(filename, &acl->name) ||
+ !tomoyo_condition(r, ptr))
continue;
error = 0;
break;
@@ -1164,6 +1180,7 @@ static int tomoyo_path_number_acl(struct
* @filename: Filename.
* @number: Number.
* @domain: Pointer to "struct tomoyo_domain_info".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
@@ -1173,12 +1190,14 @@ static inline int tomoyo_update_path_num
char *number,
struct tomoyo_domain_info *
const domain,
+ struct tomoyo_condition *cond,
const bool is_delete)
{
const u8 perm = 1 << type;
struct tomoyo_acl_info *ptr;
struct tomoyo_path_number_acl e = {
.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
+ .head.cond = cond,
.perm = perm
};
int error = is_delete ? -ENOENT : -ENOMEM;
@@ -1206,8 +1225,7 @@ static inline int tomoyo_update_path_num
struct tomoyo_path_number_acl *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
- list_add_tail_rcu(&entry->head.list,
- &domain->acl_info_list);
+ tomoyo_add_domain_acl(domain, &entry->head);
error = 0;
}
}
@@ -1572,6 +1590,7 @@ int tomoyo_path2_perm(const u8 operation
*
* @data: String to parse.
* @domain: Pointer to "struct tomoyo_domain_info".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
@@ -1579,6 +1598,7 @@ int tomoyo_path2_perm(const u8 operation
* Caller holds tomoyo_read_lock().
*/
int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
+ struct tomoyo_condition *cond,
const bool is_delete)
{
char *w[5];
@@ -1589,14 +1609,15 @@ int tomoyo_write_file_policy(char *data,
unsigned int perm;
if (sscanf(w[0], "%u", &perm) == 1)
return tomoyo_update_file_acl((u8) perm, w[1], domain,
- is_delete);
+ cond, is_delete);
goto out;
}
w[0] += 6;
for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
if (strcmp(w[0], tomoyo_path_keyword[type]))
continue;
- return tomoyo_update_path_acl(type, w[1], domain, is_delete);
+ return tomoyo_update_path_acl(type, w[1], domain, cond,
+ is_delete);
}
if (!w[2][0])
goto out;
@@ -1604,13 +1625,13 @@ int tomoyo_write_file_policy(char *data,
if (strcmp(w[0], tomoyo_path2_keyword[type]))
continue;
return tomoyo_update_path2_acl(type, w[1], w[2], domain,
- is_delete);
+ cond, is_delete);
}
for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
if (strcmp(w[0], tomoyo_path_number_keyword[type]))
continue;
return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
- is_delete);
+ cond, is_delete);
}
if (!w[3][0] || !w[4][0])
goto out;
@@ -1618,7 +1639,8 @@ int tomoyo_write_file_policy(char *data,
if (strcmp(w[0], tomoyo_path_number3_keyword[type]))
continue;
return tomoyo_update_path_number3_acl(type, w[1], w[2], w[3],
- w[4], domain, is_delete);
+ w[4], domain, cond,
+ is_delete);
}
out:
return -EINVAL;
--- security-testing-2.6.orig/security/tomoyo/gc.c
+++ security-testing-2.6/security/tomoyo/gc.c
@@ -24,6 +24,7 @@ enum tomoyo_gc_id {
TOMOYO_ID_PATTERN,
TOMOYO_ID_NO_REWRITE,
TOMOYO_ID_MANAGER,
+ TOMOYO_ID_CONDITION,
TOMOYO_ID_NAME,
TOMOYO_ID_ACL,
TOMOYO_ID_DOMAIN
@@ -97,6 +98,7 @@ static void tomoyo_del_manager(struct to

static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
{
+ tomoyo_put_condition(acl->cond);
switch (acl->type) {
case TOMOYO_TYPE_PATH_ACL:
{
@@ -183,6 +185,23 @@ static bool tomoyo_del_domain(struct tom
return true;
}

+/**
+ * tomoyo_del_condition - Delete members in "struct tomoyo_condition".
+ *
+ * @cond: Pointer to "struct tomoyo_condition".
+ */
+void tomoyo_del_condition(struct tomoyo_condition *cond)
+{
+ const u16 condc = cond->condc;
+ const u16 numbers_count = cond->numbers_count;
+ unsigned int i;
+ const struct tomoyo_condition_element *condp
+ = (const struct tomoyo_condition_element *) (cond + 1);
+ struct tomoyo_number_union *numbers_p
+ = (struct tomoyo_number_union *) (condp + condc);
+ for (i = 0; i < numbers_count; i++)
+ tomoyo_put_number_union(numbers_p++);
+}

static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
{
@@ -335,8 +354,14 @@ static void tomoyo_collect_entry(void)
head)->perm)
continue;
break;
+ case TOMOYO_TYPE_MOUNT_ACL:
+ if (!container_of(acl,
+ struct tomoyo_mount_acl,
+ head)->is_deleted)
+ continue;
+ break;
default:
- continue;
+ continue;
}
if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
list_del_rcu(&acl->list);
@@ -357,6 +382,17 @@ static void tomoyo_collect_entry(void)
}
}
{
+ struct tomoyo_condition *ptr;
+ list_for_each_entry_rcu(ptr, &tomoyo_condition_list, list) {
+ if (atomic_read(&ptr->users))
+ continue;
+ if (tomoyo_add_to_gc(TOMOYO_ID_CONDITION, ptr))
+ list_del_rcu(&ptr->list);
+ else
+ break;
+ }
+ }
+ {
int i;
for (i = 0; i < TOMOYO_MAX_HASH; i++) {
struct tomoyo_name_entry *ptr;
@@ -453,6 +489,11 @@ static void tomoyo_kfree_entry(void)
case TOMOYO_ID_MANAGER:
tomoyo_del_manager(p->element);
break;
+ case TOMOYO_ID_CONDITION:
+ tomoyo_del_condition(container_of(p->element, struct
+ tomoyo_condition,
+ list));
+ break;
case TOMOYO_ID_NAME:
tomoyo_del_name(p->element);
break;
--- security-testing-2.6.orig/security/tomoyo/memory.c
+++ security-testing-2.6/security/tomoyo/memory.c
@@ -49,10 +49,8 @@ bool tomoyo_memory_ok(void *ptr)
atomic_add(s, &tomoyo_policy_memory_size);
if (ptr && (!tomoyo_quota_for_policy ||
atomic_read(&tomoyo_policy_memory_size)
- <= tomoyo_quota_for_policy)) {
- memset(ptr, 0, s);
+ <= tomoyo_quota_for_policy))
return true;
- }
atomic_sub(s, &tomoyo_policy_memory_size);
tomoyo_warn_oom(__func__);
return false;
--- security-testing-2.6.orig/security/tomoyo/mount.c
+++ security-testing-2.6/security/tomoyo/mount.c
@@ -122,7 +122,8 @@ static int tomoyo_mount_acl2(struct tomo
!tomoyo_compare_name_union(&rtype, &acl->fs_type) ||
!tomoyo_compare_name_union(&rdir, &acl->dir_name) ||
(need_dev &&
- !tomoyo_compare_name_union(&rdev, &acl->dev_name)))
+ !tomoyo_compare_name_union(&rdev, &acl->dev_name)) ||
+ !tomoyo_condition(r, ptr))
continue;
error = 0;
break;
@@ -264,15 +265,20 @@ int tomoyo_mount_permission(char *dev_na
*
* @data: String to parse.
* @domain: Pointer to "struct tomoyo_domain_info".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
*/
int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain,
+ struct tomoyo_condition *cond,
const bool is_delete)
{
struct tomoyo_acl_info *ptr;
- struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
+ struct tomoyo_mount_acl e = {
+ .head.type = TOMOYO_TYPE_MOUNT_ACL,
+ .head.cond = cond
+ };
int error = is_delete ? -ENOENT : -ENOMEM;
char *w[4];
if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0])
@@ -297,8 +303,7 @@ int tomoyo_write_mount_policy(char *data
struct tomoyo_mount_acl *entry =
tomoyo_commit_ok(&e, sizeof(e));
if (entry) {
- list_add_tail_rcu(&entry->head.list,
- &domain->acl_info_list);
+ tomoyo_add_domain_acl(domain, &entry->head);
error = 0;
}
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/