summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/tomoyo/common.c431
-rw-r--r--security/tomoyo/common.h68
-rw-r--r--security/tomoyo/domain.c9
-rw-r--r--security/tomoyo/file.c131
-rw-r--r--security/tomoyo/mount.c3
-rw-r--r--security/tomoyo/util.c92
6 files changed, 486 insertions, 248 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index bdf1ed7..811adb5 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -9,53 +9,74 @@
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/security.h>
-#include <linux/hardirq.h>
#include "common.h"
+static struct tomoyo_profile tomoyo_default_profile = {
+ .learning = &tomoyo_default_profile.preference,
+ .permissive = &tomoyo_default_profile.preference,
+ .enforcing = &tomoyo_default_profile.preference,
+ .preference.enforcing_verbose = true,
+ .preference.learning_max_entry = 2048,
+ .preference.learning_verbose = false,
+ .preference.permissive_verbose = true
+};
+
+/* Profile version. Currently only 20090903 is defined. */
+static unsigned int tomoyo_profile_version;
+
+/* Profile table. Memory is allocated as needed. */
+static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
+
/* String table for functionality that takes 4 modes. */
static const char *tomoyo_mode_4[4] = {
"disabled", "learning", "permissive", "enforcing"
};
-/* String table for functionality that takes 2 modes. */
-static const char *tomoyo_mode_2[4] = {
- "disabled", "enabled", "enabled", "enabled"
-};
-/*
- * tomoyo_control_array is a static data which contains
- *
- * (1) functionality name used by /sys/kernel/security/tomoyo/profile .
- * (2) initial values for "struct tomoyo_profile".
- * (3) max values for "struct tomoyo_profile".
- */
-static struct {
- const char *keyword;
- unsigned int current_value;
- const unsigned int max_value;
-} tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = {
- [TOMOYO_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 },
- [TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX },
- [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 },
+/* String table for /sys/kernel/security/tomoyo/profile */
+static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+ + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+ [TOMOYO_MAC_FILE_EXECUTE] = "file::execute",
+ [TOMOYO_MAC_FILE_OPEN] = "file::open",
+ [TOMOYO_MAC_FILE_CREATE] = "file::create",
+ [TOMOYO_MAC_FILE_UNLINK] = "file::unlink",
+ [TOMOYO_MAC_FILE_MKDIR] = "file::mkdir",
+ [TOMOYO_MAC_FILE_RMDIR] = "file::rmdir",
+ [TOMOYO_MAC_FILE_MKFIFO] = "file::mkfifo",
+ [TOMOYO_MAC_FILE_MKSOCK] = "file::mksock",
+ [TOMOYO_MAC_FILE_TRUNCATE] = "file::truncate",
+ [TOMOYO_MAC_FILE_SYMLINK] = "file::symlink",
+ [TOMOYO_MAC_FILE_REWRITE] = "file::rewrite",
+ [TOMOYO_MAC_FILE_MKBLOCK] = "file::mkblock",
+ [TOMOYO_MAC_FILE_MKCHAR] = "file::mkchar",
+ [TOMOYO_MAC_FILE_LINK] = "file::link",
+ [TOMOYO_MAC_FILE_RENAME] = "file::rename",
+ [TOMOYO_MAC_FILE_CHMOD] = "file::chmod",
+ [TOMOYO_MAC_FILE_CHOWN] = "file::chown",
+ [TOMOYO_MAC_FILE_CHGRP] = "file::chgrp",
+ [TOMOYO_MAC_FILE_IOCTL] = "file::ioctl",
+ [TOMOYO_MAC_FILE_CHROOT] = "file::chroot",
+ [TOMOYO_MAC_FILE_MOUNT] = "file::mount",
+ [TOMOYO_MAC_FILE_UMOUNT] = "file::umount",
+ [TOMOYO_MAC_FILE_PIVOT_ROOT] = "file::pivot_root",
+ [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
};
-/*
- * tomoyo_profile is a structure which is used for holding the mode of access
- * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing.
- * An administrator can define up to 256 profiles.
- * The ->profile of "struct tomoyo_domain_info" is used for remembering
- * the profile's number (0 - 255) assigned to that domain.
- */
-static struct tomoyo_profile {
- unsigned int value[TOMOYO_MAX_CONTROL_INDEX];
- const struct tomoyo_path_info *comment;
-} *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
-
/* Permit policy management by non-root user? */
static bool tomoyo_manage_by_non_root;
/* Utility functions. */
/**
+ * tomoyo_yesno - Return "yes" or "no".
+ *
+ * @value: Bool value.
+ */
+static const char *tomoyo_yesno(const unsigned int value)
+{
+ return value ? "yes" : "no";
+}
+
+/**
* tomoyo_print_name_union - Print a tomoyo_name_union.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -154,80 +175,62 @@ bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
}
/**
- * tomoyo_check_flags - Check mode for specified functionality.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @index: The functionality to check mode.
- *
- * TOMOYO checks only process context.
- * This code disables TOMOYO's enforcement in case the function is called from
- * interrupt context.
- */
-unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
- const u8 index)
-{
- const u8 profile = domain->profile;
-
- if (WARN_ON(in_interrupt()))
- return 0;
- return tomoyo_policy_loaded && index < TOMOYO_MAX_CONTROL_INDEX
-#if TOMOYO_MAX_PROFILES != 256
- && profile < TOMOYO_MAX_PROFILES
-#endif
- && tomoyo_profile_ptr[profile] ?
- tomoyo_profile_ptr[profile]->value[index] : 0;
-}
-
-/**
- * tomoyo_verbose_mode - Check whether TOMOYO is verbose mode.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns true if domain policy violation warning should be printed to
- * console.
- */
-bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
-{
- return tomoyo_check_flags(domain, TOMOYO_VERBOSE) != 0;
-}
-
-/**
* tomoyo_find_or_assign_new_profile - Create a new profile.
*
* @profile: Profile number to create.
*
* Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
*/
-static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
- int profile)
+static struct tomoyo_profile *tomoyo_find_or_assign_new_profile
+(const unsigned int profile)
{
- struct tomoyo_profile *ptr = NULL;
- int i;
-
+ struct tomoyo_profile *ptr;
+ struct tomoyo_profile *entry;
if (profile >= TOMOYO_MAX_PROFILES)
return NULL;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- return NULL;
ptr = tomoyo_profile_ptr[profile];
if (ptr)
- goto ok;
- ptr = kmalloc(sizeof(*ptr), GFP_NOFS);
- if (!tomoyo_memory_ok(ptr)) {
- kfree(ptr);
- ptr = NULL;
- goto ok;
+ return ptr;
+ entry = kzalloc(sizeof(*entry), GFP_NOFS);
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ ptr = tomoyo_profile_ptr[profile];
+ if (!ptr && tomoyo_memory_ok(entry)) {
+ ptr = entry;
+ ptr->learning = &tomoyo_default_profile.preference;
+ ptr->permissive = &tomoyo_default_profile.preference;
+ ptr->enforcing = &tomoyo_default_profile.preference;
+ ptr->default_config = TOMOYO_CONFIG_DISABLED;
+ memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
+ sizeof(ptr->config));
+ mb(); /* Avoid out-of-order execution. */
+ tomoyo_profile_ptr[profile] = ptr;
+ entry = NULL;
}
- for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
- ptr->value[i] = tomoyo_control_array[i].current_value;
- mb(); /* Avoid out-of-order execution. */
- tomoyo_profile_ptr[profile] = ptr;
- ok:
mutex_unlock(&tomoyo_policy_lock);
+ out:
+ kfree(entry);
return ptr;
}
/**
- * tomoyo_write_profile - Write to profile table.
+ * tomoyo_profile - Find a profile.
+ *
+ * @profile: Profile number to find.
+ *
+ * Returns pointer to "struct tomoyo_profile".
+ */
+struct tomoyo_profile *tomoyo_profile(const u8 profile)
+{
+ struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile];
+ if (!tomoyo_policy_loaded)
+ return &tomoyo_default_profile;
+ BUG_ON(!ptr);
+ return ptr;
+}
+
+/**
+ * tomoyo_write_profile - Write profile table.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
@@ -237,64 +240,116 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
{
char *data = head->write_buf;
unsigned int i;
- unsigned int value;
+ int value;
+ int mode;
+ u8 config;
+ bool use_default = false;
char *cp;
struct tomoyo_profile *profile;
- unsigned long num;
-
- cp = strchr(data, '-');
- if (cp)
- *cp = '\0';
- if (strict_strtoul(data, 10, &num))
- return -EINVAL;
- if (cp)
+ if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1)
+ return 0;
+ i = simple_strtoul(data, &cp, 10);
+ if (data == cp) {
+ profile = &tomoyo_default_profile;
+ } else {
+ if (*cp != '-')
+ return -EINVAL;
data = cp + 1;
- profile = tomoyo_find_or_assign_new_profile(num);
- if (!profile)
- return -EINVAL;
+ profile = tomoyo_find_or_assign_new_profile(i);
+ if (!profile)
+ return -EINVAL;
+ }
cp = strchr(data, '=');
if (!cp)
return -EINVAL;
- *cp = '\0';
+ *cp++ = '\0';
+ if (profile != &tomoyo_default_profile)
+ use_default = strstr(cp, "use_default") != NULL;
+ if (strstr(cp, "verbose=yes"))
+ value = 1;
+ else if (strstr(cp, "verbose=no"))
+ value = 0;
+ else
+ value = -1;
+ if (!strcmp(data, "PREFERENCE::enforcing")) {
+ if (use_default) {
+ profile->enforcing = &tomoyo_default_profile.preference;
+ return 0;
+ }
+ profile->enforcing = &profile->preference;
+ if (value >= 0)
+ profile->preference.enforcing_verbose = value;
+ return 0;
+ }
+ if (!strcmp(data, "PREFERENCE::permissive")) {
+ if (use_default) {
+ profile->permissive = &tomoyo_default_profile.preference;
+ return 0;
+ }
+ profile->permissive = &profile->preference;
+ if (value >= 0)
+ profile->preference.permissive_verbose = value;
+ return 0;
+ }
+ if (!strcmp(data, "PREFERENCE::learning")) {
+ char *cp2;
+ if (use_default) {
+ profile->learning = &tomoyo_default_profile.preference;
+ return 0;
+ }
+ profile->learning = &profile->preference;
+ if (value >= 0)
+ profile->preference.learning_verbose = value;
+ cp2 = strstr(cp, "max_entry=");
+ if (cp2)
+ sscanf(cp2 + 10, "%u",
+ &profile->preference.learning_max_entry);
+ return 0;
+ }
+ if (profile == &tomoyo_default_profile)
+ return -EINVAL;
if (!strcmp(data, "COMMENT")) {
const struct tomoyo_path_info *old_comment = profile->comment;
- profile->comment = tomoyo_get_name(cp + 1);
+ profile->comment = tomoyo_get_name(cp);
tomoyo_put_name(old_comment);
return 0;
}
- for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
- if (strcmp(data, tomoyo_control_array[i].keyword))
- continue;
- if (sscanf(cp + 1, "%u", &value) != 1) {
- int j;
- const char **modes;
- switch (i) {
- case TOMOYO_VERBOSE:
- modes = tomoyo_mode_2;
- break;
- default:
- modes = tomoyo_mode_4;
- break;
- }
- for (j = 0; j < 4; j++) {
- if (strcmp(cp + 1, modes[j]))
- continue;
- value = j;
- break;
- }
- if (j == 4)
- return -EINVAL;
- } else if (value > tomoyo_control_array[i].max_value) {
- value = tomoyo_control_array[i].max_value;
+ if (!strcmp(data, "CONFIG")) {
+ i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
+ config = profile->default_config;
+ } else if (tomoyo_str_starts(&data, "CONFIG::")) {
+ config = 0;
+ for (i = 0; i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
+ if (strcmp(data, tomoyo_mac_keywords[i]))
+ continue;
+ config = profile->config[i];
+ break;
}
- profile->value[i] = value;
- return 0;
+ if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+ return -EINVAL;
+ } else {
+ return -EINVAL;
}
- return -EINVAL;
+ if (use_default) {
+ config = TOMOYO_CONFIG_USE_DEFAULT;
+ } else {
+ for (mode = 3; mode >= 0; mode--)
+ if (strstr(cp, tomoyo_mode_4[mode]))
+ /*
+ * Update lower 3 bits in order to distinguish
+ * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'.
+ */
+ config = (config & ~7) | mode;
+ }
+ if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+ profile->config[i] = config;
+ else if (config != TOMOYO_CONFIG_USE_DEFAULT)
+ profile->default_config = config;
+ return 0;
}
/**
- * tomoyo_read_profile - Read from profile table.
+ * tomoyo_read_profile - Read profile table.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
@@ -302,53 +357,82 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
*/
static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
{
- static const int total = TOMOYO_MAX_CONTROL_INDEX + 1;
- int step;
-
+ int index;
if (head->read_eof)
return 0;
- for (step = head->read_step; step < TOMOYO_MAX_PROFILES * total;
- step++) {
- const u8 index = step / total;
- u8 type = step % total;
+ if (head->read_bit)
+ goto body;
+ tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903");
+ tomoyo_io_printf(head, "PREFERENCE::learning={ verbose=%s "
+ "max_entry=%u }\n",
+ tomoyo_yesno(tomoyo_default_profile.preference.
+ learning_verbose),
+ tomoyo_default_profile.preference.learning_max_entry);
+ tomoyo_io_printf(head, "PREFERENCE::permissive={ verbose=%s }\n",
+ tomoyo_yesno(tomoyo_default_profile.preference.
+ permissive_verbose));
+ tomoyo_io_printf(head, "PREFERENCE::enforcing={ verbose=%s }\n",
+ tomoyo_yesno(tomoyo_default_profile.preference.
+ enforcing_verbose));
+ head->read_bit = 1;
+ body:
+ for (index = head->read_step; index < TOMOYO_MAX_PROFILES; index++) {
+ bool done;
+ u8 config;
+ int i;
+ int pos;
const struct tomoyo_profile *profile
= tomoyo_profile_ptr[index];
- head->read_step = step;
+ const struct tomoyo_path_info *comment;
+ head->read_step = index;
if (!profile)
continue;
- if (!type) { /* Print profile' comment tag. */
- if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
- index, profile->comment ?
- profile->comment->name : ""))
- break;
- continue;
- }
- type--;
- if (type < TOMOYO_MAX_CONTROL_INDEX) {
- const unsigned int value = profile->value[type];
- const char **modes = NULL;
- const char *keyword
- = tomoyo_control_array[type].keyword;
- switch (tomoyo_control_array[type].max_value) {
- case 3:
- modes = tomoyo_mode_4;
- break;
- case 1:
- modes = tomoyo_mode_2;
- break;
- }
- if (modes) {
- if (!tomoyo_io_printf(head, "%u-%s=%s\n", index,
- keyword, modes[value]))
- break;
- } else {
- if (!tomoyo_io_printf(head, "%u-%s=%u\n", index,
- keyword, value))
- break;
- }
+ pos = head->read_avail;
+ comment = profile->comment;
+ done = tomoyo_io_printf(head, "%u-COMMENT=%s\n", index,
+ comment ? comment->name : "");
+ if (!done)
+ goto out;
+ config = profile->default_config;
+ if (!tomoyo_io_printf(head, "%u-CONFIG={ mode=%s }\n", index,
+ tomoyo_mode_4[config & 3]))
+ goto out;
+ for (i = 0; i < TOMOYO_MAX_MAC_INDEX +
+ TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
+ config = profile->config[i];
+ if (config == TOMOYO_CONFIG_USE_DEFAULT)
+ continue;
+ if (!tomoyo_io_printf(head,
+ "%u-CONFIG::%s={ mode=%s }\n",
+ index, tomoyo_mac_keywords[i],
+ tomoyo_mode_4[config & 3]))
+ goto out;
}
+ if (profile->learning != &tomoyo_default_profile.preference &&
+ !tomoyo_io_printf(head, "%u-PREFERENCE::learning={ "
+ "verbose=%s max_entry=%u }\n", index,
+ tomoyo_yesno(profile->preference.
+ learning_verbose),
+ profile->preference.learning_max_entry))
+ goto out;
+ if (profile->permissive != &tomoyo_default_profile.preference
+ && !tomoyo_io_printf(head, "%u-PREFERENCE::permissive={ "
+ "verbose=%s }\n", index,
+ tomoyo_yesno(profile->preference.
+ permissive_verbose)))
+ goto out;
+ if (profile->enforcing != &tomoyo_default_profile.preference &&
+ !tomoyo_io_printf(head, "%u-PREFERENCE::enforcing={ "
+ "verbose=%s }\n", index,
+ tomoyo_yesno(profile->preference.
+ enforcing_verbose)))
+ goto out;
+ continue;
+ out:
+ head->read_avail = pos;
+ break;
}
- if (step == TOMOYO_MAX_PROFILES * total)
+ if (index == TOMOYO_MAX_PROFILES)
head->read_eof = true;
return 0;
}
@@ -1595,7 +1679,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
static int tomoyo_read_version(struct tomoyo_io_buffer *head)
{
if (!head->read_eof) {
- tomoyo_io_printf(head, "2.2.0");
+ tomoyo_io_printf(head, "2.3.0-pre");
head->read_eof = true;
}
return 0;
@@ -1915,6 +1999,9 @@ void tomoyo_check_profile(void)
profile, domain->domainname->name);
}
tomoyo_read_unlock(idx);
- printk(KERN_INFO "TOMOYO: 2.2.0 2009/04/01\n");
+ if (tomoyo_profile_version != 20090903)
+ panic("Profile version %u is not supported.\n",
+ tomoyo_profile_version);
+ printk(KERN_INFO "TOMOYO: 2.3.0-pre 2010/06/03\n");
printk(KERN_INFO "Mandatory Access Control activated.\n");
}
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 54db39a..c777c59 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -42,7 +42,8 @@ enum tomoyo_mode_index {
TOMOYO_CONFIG_DISABLED,
TOMOYO_CONFIG_LEARNING,
TOMOYO_CONFIG_PERMISSIVE,
- TOMOYO_CONFIG_ENFORCING
+ TOMOYO_CONFIG_ENFORCING,
+ TOMOYO_CONFIG_USE_DEFAULT = 255
};
/* Keywords for ACLs. */
@@ -75,14 +76,6 @@ enum tomoyo_mode_index {
#define TOMOYO_VALUE_TYPE_HEXADECIMAL 3
/* Index numbers for Access Controls. */
-enum tomoyo_mac_index {
- TOMOYO_MAC_FOR_FILE, /* domain_policy.conf */
- TOMOYO_MAX_ACCEPT_ENTRY,
- TOMOYO_VERBOSE,
- TOMOYO_MAX_CONTROL_INDEX
-};
-
-/* Index numbers for Access Controls. */
enum tomoyo_acl_entry_type_index {
TOMOYO_TYPE_PATH_ACL,
TOMOYO_TYPE_PATH2_ACL,
@@ -157,6 +150,38 @@ enum tomoyo_securityfs_interface_index {
TOMOYO_MANAGER
};
+enum tomoyo_mac_index {
+ TOMOYO_MAC_FILE_EXECUTE,
+ TOMOYO_MAC_FILE_OPEN,
+ TOMOYO_MAC_FILE_CREATE,
+ TOMOYO_MAC_FILE_UNLINK,
+ TOMOYO_MAC_FILE_MKDIR,
+ TOMOYO_MAC_FILE_RMDIR,
+ TOMOYO_MAC_FILE_MKFIFO,
+ TOMOYO_MAC_FILE_MKSOCK,
+ TOMOYO_MAC_FILE_TRUNCATE,
+ TOMOYO_MAC_FILE_SYMLINK,
+ TOMOYO_MAC_FILE_REWRITE,
+ TOMOYO_MAC_FILE_MKBLOCK,
+ TOMOYO_MAC_FILE_MKCHAR,
+ TOMOYO_MAC_FILE_LINK,
+ TOMOYO_MAC_FILE_RENAME,
+ TOMOYO_MAC_FILE_CHMOD,
+ TOMOYO_MAC_FILE_CHOWN,
+ TOMOYO_MAC_FILE_CHGRP,
+ TOMOYO_MAC_FILE_IOCTL,
+ TOMOYO_MAC_FILE_CHROOT,
+ TOMOYO_MAC_FILE_MOUNT,
+ TOMOYO_MAC_FILE_UMOUNT,
+ TOMOYO_MAC_FILE_PIVOT_ROOT,
+ TOMOYO_MAX_MAC_INDEX
+};
+
+enum tomoyo_mac_category_index {
+ TOMOYO_MAC_CATEGORY_FILE,
+ TOMOYO_MAX_MAC_CATEGORY_INDEX
+};
+
#define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */
/********** Structure definitions. **********/
@@ -174,6 +199,7 @@ struct tomoyo_request_info {
u8 retry;
u8 profile;
u8 mode; /* One of tomoyo_mode_index . */
+ u8 type;
};
/*
@@ -649,6 +675,23 @@ struct tomoyo_policy_manager_entry {
bool is_deleted; /* True if this entry is deleted. */
};
+struct tomoyo_preference {
+ unsigned int learning_max_entry;
+ bool enforcing_verbose;
+ bool learning_verbose;
+ bool permissive_verbose;
+};
+
+struct tomoyo_profile {
+ const struct tomoyo_path_info *comment;
+ struct tomoyo_preference *learning;
+ struct tomoyo_preference *permissive;
+ struct tomoyo_preference *enforcing;
+ struct tomoyo_preference preference;
+ u8 default_config;
+ u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX];
+};
+
/********** Function prototypes. **********/
extern asmlinkage long sys_getpid(void);
@@ -685,6 +728,7 @@ bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
/* Check whether the given number matches the given number_union. */
bool tomoyo_compare_number_union(const unsigned long value,
const struct tomoyo_number_union *ptr);
+int tomoyo_get_mode(const u8 profile, const u8 index);
/* Transactional sprintf() for policy dump. */
bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
@@ -747,7 +791,8 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain);
const char *tomoyo_path2keyword(const u8 operation);
/* Fill "struct tomoyo_request_info". */
int tomoyo_init_request_info(struct tomoyo_request_info *r,
- struct tomoyo_domain_info *domain);
+ struct tomoyo_domain_info *domain,
+ const u8 index);
/* Check permission for mount operation. */
int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
unsigned long flags, void *data_page);
@@ -794,6 +839,7 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
domainname,
const u8 profile);
+struct tomoyo_profile *tomoyo_profile(const u8 profile);
/* Allocate memory for "struct tomoyo_path_group". */
struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name);
struct tomoyo_number_group *tomoyo_get_number_group(const char *group_name);
@@ -844,7 +890,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
/* Initialize mm related code. */
void __init tomoyo_mm_init(void);
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
+int tomoyo_check_exec_perm(struct tomoyo_request_info *r,
const struct tomoyo_path_info *filename);
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct path *path, const int flag);
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index a07ca6d..09ec37c 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -812,8 +812,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
struct tomoyo_domain_info *domain = NULL;
const char *old_domain_name = old_domain->domainname->name;
const char *original_name = bprm->filename;
- const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
+ u8 mode;
+ bool is_enforce;
int retval = -ENOMEM;
bool need_kfree = false;
struct tomoyo_path_info rn = { }; /* real name */
@@ -822,7 +822,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
ln.name = tomoyo_get_last_name(old_domain);
tomoyo_fill_path_info(&ln);
- tomoyo_init_request_info(&r, NULL);
+ mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+ is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
if (!tmp)
goto out;
@@ -880,7 +881,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
}
/* Check execute permission. */
- retval = tomoyo_check_exec_perm(old_domain, &rn);
+ retval = tomoyo_check_exec_perm(&r, &rn);
if (retval == TOMOYO_RETRY_REQUEST)
goto retry;
if (retval < 0)
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 83fa17a..8e51348 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -51,6 +51,42 @@ static const char *tomoyo_path_number_keyword
[TOMOYO_TYPE_CHGRP] = "chgrp",
};
+static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
+ [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
+ [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE,
+ [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN,
+ [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN,
+ [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK,
+ [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR,
+ [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE,
+ [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK,
+ [TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE,
+ [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT,
+ [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT,
+};
+
+static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_PATH_NUMBER3_OPERATION] = {
+ [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
+ [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR,
+};
+
+static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
+ [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK,
+ [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME,
+ [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
+};
+
+static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+ [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
+ [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR,
+ [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
+ [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
+ [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL,
+ [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD,
+ [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN,
+ [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP,
+};
+
void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
{
if (!ptr)
@@ -1057,6 +1093,10 @@ static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
int error;
next:
+ r->type = tomoyo_p2mac[operation];
+ r->mode = tomoyo_get_mode(r->profile, r->type);
+ if (r->mode == TOMOYO_CONFIG_DISABLED)
+ return 0;
do {
error = tomoyo_path_acl(r, filename, 1 << operation);
if (!error)
@@ -1249,8 +1289,8 @@ int tomoyo_path_number_perm(const u8 type, struct path *path,
struct tomoyo_path_info buf;
int idx;
- if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
- !path->mnt || !path->dentry)
+ if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
+ == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
return 0;
idx = tomoyo_read_lock();
if (!tomoyo_get_realpath(&buf, path))
@@ -1269,21 +1309,19 @@ int tomoyo_path_number_perm(const u8 type, struct path *path,
/**
* tomoyo_check_exec_perm - Check permission for "execute".
*
- * @domain: Pointer to "struct tomoyo_domain_info".
+ * @r: Pointer to "struct tomoyo_request_info".
* @filename: Check permission for "execute".
*
* Returns 0 on success, negativevalue otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
+int tomoyo_check_exec_perm(struct tomoyo_request_info *r,
const struct tomoyo_path_info *filename)
{
- struct tomoyo_request_info r;
-
- if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED)
+ if (r->mode == TOMOYO_CONFIG_DISABLED)
return 0;
- return tomoyo_file_perm(&r, filename, 1);
+ return tomoyo_file_perm(r, filename, 1);
}
/**
@@ -1304,17 +1342,11 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct tomoyo_request_info r;
int idx;
- if (tomoyo_init_request_info(&r, domain) == TOMOYO_CONFIG_DISABLED ||
- !path->mnt)
- return 0;
- if (acc_mode == 0)
- return 0;
- if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
- /*
- * I don't check directories here because mkdir() and rmdir()
- * don't call me.
- */
+ if (!path->mnt ||
+ (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
return 0;
+ buf.name = NULL;
+ r.mode = TOMOYO_CONFIG_DISABLED;
idx = tomoyo_read_lock();
if (!tomoyo_get_realpath(&buf, path))
goto out;
@@ -1324,15 +1356,26 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
* we need to check "allow_rewrite" permission when the filename is not
* opened for append mode or the filename is truncated at open time.
*/
- if ((acc_mode & MAY_WRITE) &&
- ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
- (tomoyo_is_no_rewrite_file(&buf))) {
- error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, &buf);
+ if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
+ && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
+ != TOMOYO_CONFIG_DISABLED) {
+ if (!tomoyo_get_realpath(&buf, path)) {
+ error = -ENOMEM;
+ goto out;
+ }
+ if (tomoyo_is_no_rewrite_file(&buf))
+ error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
+ &buf);
}
- if (!error)
+ if (!error && acc_mode &&
+ tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
+ != TOMOYO_CONFIG_DISABLED) {
+ if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
+ error = -ENOMEM;
+ goto out;
+ }
error = tomoyo_file_perm(&r, &buf, acc_mode);
- if (!error && (flag & O_TRUNC))
- error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, &buf);
+ }
out:
kfree(buf.name);
tomoyo_read_unlock(idx);
@@ -1356,9 +1399,12 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
struct tomoyo_request_info r;
int idx;
- if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
- !path->mnt)
+ if (!path->mnt)
+ return 0;
+ if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
+ == TOMOYO_CONFIG_DISABLED)
return 0;
+ buf.name = NULL;
idx = tomoyo_read_lock();
if (!tomoyo_get_realpath(&buf, path))
goto out;
@@ -1371,6 +1417,7 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
break;
case TOMOYO_TYPE_RMDIR:
case TOMOYO_TYPE_CHROOT:
+ case TOMOYO_TYPE_UMOUNT:
tomoyo_add_slash(&buf);
break;
}
@@ -1442,8 +1489,9 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path,
struct tomoyo_path_info buf;
int idx;
- if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
- !path->mnt)
+ if (!path->mnt ||
+ tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
+ == TOMOYO_CONFIG_DISABLED)
return 0;
idx = tomoyo_read_lock();
error = -ENOMEM;
@@ -1477,8 +1525,9 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
struct tomoyo_request_info r;
int idx;
- if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
- !path1->mnt || !path2->mnt)
+ if (!path1->mnt || !path2->mnt ||
+ tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
+ == TOMOYO_CONFIG_DISABLED)
return 0;
buf1.name = NULL;
buf2.name = NULL;
@@ -1486,13 +1535,19 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
if (!tomoyo_get_realpath(&buf1, path1) ||
!tomoyo_get_realpath(&buf2, path2))
goto out;
- {
- struct dentry *dentry = path1->dentry;
- if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
- tomoyo_add_slash(&buf1);
- tomoyo_add_slash(&buf2);
- }
- }
+ switch (operation) {
+ struct dentry *dentry;
+ case TOMOYO_TYPE_RENAME:
+ case TOMOYO_TYPE_LINK:
+ dentry = path1->dentry;
+ if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
+ break;
+ /* fall through */
+ case TOMOYO_TYPE_PIVOT_ROOT:
+ tomoyo_add_slash(&buf1);
+ tomoyo_add_slash(&buf2);
+ break;
+ }
do {
error = tomoyo_path2_acl(&r, operation, &buf1, &buf2);
if (!error)
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
index 7c1c7fd..77ee8bf 100644
--- a/security/tomoyo/mount.c
+++ b/security/tomoyo/mount.c
@@ -248,7 +248,8 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
int error;
int idx;
- if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED)
+ if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
+ == TOMOYO_CONFIG_DISABLED)
return 0;
if (!type)
type = "<NULL>";
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
index 592b76a..307793e 100644
--- a/security/tomoyo/util.c
+++ b/security/tomoyo/util.c
@@ -792,25 +792,67 @@ const char *tomoyo_get_exe(void)
}
/**
+ * tomoyo_get_mode - Get MAC mode.
+ *
+ * @profile: Profile number.
+ * @index: Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_get_mode(const u8 profile, const u8 index)
+{
+ u8 mode;
+ const u8 category = TOMOYO_MAC_CATEGORY_FILE;
+ if (!tomoyo_policy_loaded)
+ return TOMOYO_CONFIG_DISABLED;
+ mode = tomoyo_profile(profile)->config[index];
+ if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+ mode = tomoyo_profile(profile)->config[category];
+ if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+ mode = tomoyo_profile(profile)->default_config;
+ return mode & 3;
+}
+
+/**
* tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
*
* @r: Pointer to "struct tomoyo_request_info" to initialize.
* @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
+ * @index: Index number of functionality.
*
* Returns mode.
*/
int tomoyo_init_request_info(struct tomoyo_request_info *r,
- struct tomoyo_domain_info *domain)
+ struct tomoyo_domain_info *domain, const u8 index)
{
+ u8 profile;
memset(r, 0, sizeof(*r));
if (!domain)
domain = tomoyo_domain();
r->domain = domain;
- r->mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+ profile = domain->profile;
+ r->profile = profile;
+ r->type = index;
+ r->mode = tomoyo_get_mode(profile, index);
return r->mode;
}
/**
+ * tomoyo_last_word - Get last component of a line.
+ *
+ * @line: A line.
+ *
+ * Returns the last word of a line.
+ */
+static const char *tomoyo_last_word(const char *name)
+{
+ const char *cp = strrchr(name, ' ');
+ if (cp)
+ return cp + 1;
+ return name;
+}
+
+/**
* tomoyo_warn_log - Print warning or error message on console.
*
* @r: Pointer to "struct tomoyo_request_info".
@@ -818,29 +860,34 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r,
*/
void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
{
- int len = PAGE_SIZE;
va_list args;
char *buffer;
- if (!tomoyo_verbose_mode(r->domain))
- return;
- while (1) {
- int len2;
- buffer = kmalloc(len, GFP_NOFS);
- if (!buffer)
+ const struct tomoyo_domain_info * const domain = r->domain;
+ const struct tomoyo_profile *profile = tomoyo_profile(domain->profile);
+ switch (r->mode) {
+ case TOMOYO_CONFIG_ENFORCING:
+ if (!profile->enforcing->enforcing_verbose)
return;
- va_start(args, fmt);
- len2 = vsnprintf(buffer, len - 1, fmt, args);
- va_end(args);
- if (len2 <= len - 1) {
- buffer[len2] = '\0';
- break;
- }
- len = len2 + 1;
- kfree(buffer);
+ break;
+ case TOMOYO_CONFIG_PERMISSIVE:
+ if (!profile->permissive->permissive_verbose)
+ return;
+ break;
+ case TOMOYO_CONFIG_LEARNING:
+ if (!profile->learning->learning_verbose)
+ return;
+ break;
}
- printk(KERN_WARNING "TOMOYO-%s: Access %s denied for %s\n",
- r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING",
- buffer, tomoyo_get_last_name(r->domain));
+ buffer = kmalloc(4096, GFP_NOFS);
+ if (!buffer)
+ return;
+ va_start(args, fmt);
+ vsnprintf(buffer, 4095, fmt, args);
+ va_end(args);
+ buffer[4095] = '\0';
+ printk(KERN_WARNING "%s: Access %s denied for %s\n",
+ r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
+ tomoyo_last_word(domain->domainname->name));
kfree(buffer);
}
@@ -903,7 +950,8 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
count++;
}
}
- if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
+ if (count < tomoyo_profile(domain->profile)->learning->
+ learning_max_entry)
return true;
if (!domain->quota_warned) {
domain->quota_warned = true;
OpenPOWER on IntegriCloud