#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.
*
return true;
}
-/**
- * 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.
*
*
* 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".
*
{
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".
- *
- * Returns 0.
*/
-static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
+static void 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;
+ return;
+ 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;
}
-/*
- * tomoyo_policy_manager_list is used for holding list of domainnames or
- * programs which are permitted to modify configuration via
- * /sys/kernel/security/tomoyo/ interface.
- *
- * An entry is added by
- *
- * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \
- * /sys/kernel/security/tomoyo/manager
- * (if you want to specify by a domainname)
- *
- * or
- *
- * # echo '/usr/sbin/tomoyo-editpolicy' > /sys/kernel/security/tomoyo/manager
- * (if you want to specify by a program's location)
- *
- * and is deleted by
- *
- * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \
- * /sys/kernel/security/tomoyo/manager
- *
- * or
- *
- * # echo 'delete /usr/sbin/tomoyo-editpolicy' > \
- * /sys/kernel/security/tomoyo/manager
- *
- * and all entries are retrieved by
- *
- * # cat /sys/kernel/security/tomoyo/manager
- */
-LIST_HEAD(tomoyo_policy_manager_list);
+static bool tomoyo_same_manager_entry(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
+{
+ return container_of(a, struct tomoyo_policy_manager_entry, head)
+ ->manager ==
+ container_of(b, struct tomoyo_policy_manager_entry, head)
+ ->manager;
+}
/**
* tomoyo_update_manager_entry - Add a manager entry.
static int tomoyo_update_manager_entry(const char *manager,
const bool is_delete)
{
- struct tomoyo_policy_manager_entry *ptr;
struct tomoyo_policy_manager_entry e = { };
- int error = is_delete ? -ENOENT : -ENOMEM;
+ int error;
- if (tomoyo_is_domain_def(manager)) {
- if (!tomoyo_is_correct_domain(manager))
+ if (tomoyo_domain_def(manager)) {
+ if (!tomoyo_correct_domain(manager))
return -EINVAL;
e.is_domain = true;
} else {
- if (!tomoyo_is_correct_path(manager))
+ if (!tomoyo_correct_path(manager))
return -EINVAL;
}
e.manager = tomoyo_get_name(manager);
if (!e.manager)
return -ENOMEM;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
- if (ptr->manager != e.manager)
- continue;
- ptr->is_deleted = is_delete;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_policy_manager_entry *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->list,
- &tomoyo_policy_manager_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
- out:
+ error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+ &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+ tomoyo_same_manager_entry);
tomoyo_put_name(e.manager);
return error;
}
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
- * Returns 0.
- *
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
+static void tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
{
- struct list_head *pos;
bool done = true;
if (head->read_eof)
- return 0;
- list_for_each_cookie(pos, head->read_var2,
- &tomoyo_policy_manager_list) {
- struct tomoyo_policy_manager_entry *ptr;
- ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
- list);
- if (ptr->is_deleted)
+ return;
+ list_for_each_cookie(head->read_var2,
+ &tomoyo_policy_list[TOMOYO_ID_MANAGER]) {
+ struct tomoyo_policy_manager_entry *ptr =
+ list_entry(head->read_var2, typeof(*ptr), head.list);
+ if (ptr->head.is_deleted)
continue;
done = tomoyo_io_printf(head, "%s\n", ptr->manager->name);
if (!done)
break;
}
head->read_eof = done;
- return 0;
}
/**
- * tomoyo_is_policy_manager - Check whether the current process is a policy manager.
+ * tomoyo_policy_manager - Check whether the current process is a policy manager.
*
* Returns true if the current process is permitted to modify policy
* via /sys/kernel/security/tomoyo/ interface.
*
* Caller holds tomoyo_read_lock().
*/
-static bool tomoyo_is_policy_manager(void)
+static bool tomoyo_policy_manager(void)
{
struct tomoyo_policy_manager_entry *ptr;
const char *exe;
return true;
if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
return false;
- list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
- if (!ptr->is_deleted && ptr->is_domain
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+ head.list) {
+ if (!ptr->head.is_deleted && ptr->is_domain
&& !tomoyo_pathcmp(domainname, ptr->manager)) {
found = true;
break;
exe = tomoyo_get_exe();
if (!exe)
return false;
- list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
- if (!ptr->is_deleted && !ptr->is_domain
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+ head.list) {
+ if (!ptr->head.is_deleted && !ptr->is_domain
&& !strcmp(exe, ptr->manager->name)) {
found = true;
break;
}
/**
- * tomoyo_is_select_one - Parse select command.
+ * tomoyo_select_one - Parse select command.
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @data: String to parse.
*
* Caller holds tomoyo_read_lock().
*/
-static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
- const char *data)
+static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data)
{
unsigned int pid;
struct tomoyo_domain_info *domain = NULL;
bool global_pid = false;
+ if (!strcmp(data, "allow_execute")) {
+ head->print_execute_only = true;
+ return true;
+ }
if (sscanf(data, "pid=%u", &pid) == 1 ||
(global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
struct task_struct *p;
read_unlock(&tasklist_lock);
rcu_read_unlock();
} else if (!strncmp(data, "domain=", 7)) {
- if (tomoyo_is_domain_def(data + 7))
+ if (tomoyo_domain_def(data + 7))
domain = tomoyo_find_domain(data + 7);
} else
return false;
tomoyo_io_printf(head, "# select %s\n", data);
head->read_single_domain = true;
head->read_eof = !domain;
- if (domain) {
- struct tomoyo_domain_info *d;
- head->read_var1 = NULL;
- list_for_each_entry_rcu(d, &tomoyo_domain_list, list) {
- if (d == domain)
- break;
- head->read_var1 = &d->list;
- }
- head->read_var2 = NULL;
- head->read_bit = 0;
- head->read_step = 0;
- if (domain->is_deleted)
- tomoyo_io_printf(head, "# This is a deleted domain.\n");
- }
+ head->read_var1 = &domain->list;
+ head->read_var2 = NULL;
+ head->read_bit = 0;
+ head->read_step = 0;
+ if (domain && domain->is_deleted)
+ tomoyo_io_printf(head, "# This is a deleted domain.\n");
return true;
}
is_delete = true;
else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT))
is_select = true;
- if (is_select && tomoyo_is_select_one(head, data))
+ if (is_select && tomoyo_select_one(head, data))
return 0;
/* Don't allow updating policies by non manager programs. */
- if (!tomoyo_is_policy_manager())
+ if (!tomoyo_policy_manager())
return -EPERM;
- if (tomoyo_is_domain_def(data)) {
+ if (tomoyo_domain_def(data)) {
domain = NULL;
if (is_delete)
tomoyo_delete_domain(data);
for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
if (!(perm & (1 << bit)))
continue;
+ if (head->print_execute_only && bit != TOMOYO_TYPE_EXECUTE)
+ continue;
/* Print "read/write" instead of "read" and "write". */
if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE)
&& (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
continue;
pos = head->read_avail;
if (!tomoyo_io_printf(head, "allow_%s ",
- tomoyo_path2keyword(bit)) ||
+ tomoyo_path_keyword[bit]) ||
!tomoyo_print_name_union(head, &ptr->name) ||
!tomoyo_io_printf(head, "\n"))
goto out;
continue;
pos = head->read_avail;
if (!tomoyo_io_printf(head, "allow_%s ",
- tomoyo_path22keyword(bit)) ||
+ tomoyo_path2_keyword[bit]) ||
!tomoyo_print_name_union(head, &ptr->name1) ||
!tomoyo_print_name_union(head, &ptr->name2) ||
!tomoyo_io_printf(head, "\n"))
continue;
pos = head->read_avail;
if (!tomoyo_io_printf(head, "allow_%s",
- tomoyo_path_number2keyword(bit)) ||
+ tomoyo_path_number_keyword[bit]) ||
!tomoyo_print_name_union(head, &ptr->name) ||
!tomoyo_print_number_union(head, &ptr->number) ||
!tomoyo_io_printf(head, "\n"))
}
/**
- * tomoyo_print_path_number3_acl - Print a path_number3 ACL entry.
+ * tomoyo_print_mkdev_acl - Print a mkdev ACL entry.
*
* @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr: Pointer to "struct tomoyo_path_number3_acl".
+ * @ptr: Pointer to "struct tomoyo_mkdev_acl".
*
* Returns true on success, false otherwise.
*/
-static bool tomoyo_print_path_number3_acl(struct tomoyo_io_buffer *head,
- struct tomoyo_path_number3_acl *ptr)
+static bool tomoyo_print_mkdev_acl(struct tomoyo_io_buffer *head,
+ struct tomoyo_mkdev_acl *ptr)
{
int pos;
u8 bit;
const u16 perm = ptr->perm;
- for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_NUMBER3_OPERATION;
+ for (bit = head->read_bit; bit < TOMOYO_MAX_MKDEV_OPERATION;
bit++) {
if (!(perm & (1 << bit)))
continue;
pos = head->read_avail;
if (!tomoyo_io_printf(head, "allow_%s",
- tomoyo_path_number32keyword(bit)) ||
+ tomoyo_mkdev_keyword[bit]) ||
!tomoyo_print_name_union(head, &ptr->name) ||
!tomoyo_print_number_union(head, &ptr->mode) ||
!tomoyo_print_number_union(head, &ptr->major) ||
struct tomoyo_mount_acl *ptr)
{
const int pos = head->read_avail;
- if (ptr->is_deleted)
- return true;
if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_MOUNT) ||
!tomoyo_print_name_union(head, &ptr->dev_name) ||
!tomoyo_print_name_union(head, &ptr->dir_name) ||
{
const u8 acl_type = ptr->type;
+ if (ptr->is_deleted)
+ return true;
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);
}
+ if (head->print_execute_only)
+ return true;
if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
struct tomoyo_path2_acl *acl
= container_of(ptr, struct tomoyo_path2_acl, head);
head);
return tomoyo_print_path_number_acl(head, acl);
}
- if (acl_type == TOMOYO_TYPE_PATH_NUMBER3_ACL) {
- struct tomoyo_path_number3_acl *acl
- = container_of(ptr, struct tomoyo_path_number3_acl,
+ if (acl_type == TOMOYO_TYPE_MKDEV_ACL) {
+ struct tomoyo_mkdev_acl *acl
+ = container_of(ptr, struct tomoyo_mkdev_acl,
head);
- return tomoyo_print_path_number3_acl(head, acl);
+ return tomoyo_print_mkdev_acl(head, acl);
}
if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
struct tomoyo_mount_acl *acl
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
- * Returns 0.
- *
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
+static void tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
{
- struct list_head *dpos;
- struct list_head *apos;
bool done = true;
if (head->read_eof)
- return 0;
+ return;
if (head->read_step == 0)
head->read_step = 1;
- list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
- struct tomoyo_domain_info *domain;
+ list_for_each_cookie(head->read_var1, &tomoyo_domain_list) {
+ struct tomoyo_domain_info *domain =
+ list_entry(head->read_var1, typeof(*domain), list);
const char *quota_exceeded = "";
const char *transition_failed = "";
const char *ignore_global_allow_read = "";
- domain = list_entry(dpos, struct tomoyo_domain_info, list);
if (head->read_step != 1)
goto acl_loop;
if (domain->is_deleted && !head->read_single_domain)
if (head->read_step == 3)
goto tail_mark;
/* Print ACL entries in the domain. */
- list_for_each_cookie(apos, head->read_var2,
+ list_for_each_cookie(head->read_var2,
&domain->acl_info_list) {
- struct tomoyo_acl_info *ptr
- = list_entry(apos, struct tomoyo_acl_info,
- list);
+ struct tomoyo_acl_info *ptr =
+ list_entry(head->read_var2, typeof(*ptr), list);
done = tomoyo_print_entry(head, ptr);
if (!done)
break;
}
if (!done)
break;
+ head->read_var2 = NULL;
head->read_step = 3;
tail_mark:
done = tomoyo_io_printf(head, "\n");
break;
}
head->read_eof = done;
- return 0;
}
/**
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
+static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
{
- struct list_head *pos;
bool done = true;
if (head->read_eof)
- return 0;
- list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
- struct tomoyo_domain_info *domain;
- domain = list_entry(pos, struct tomoyo_domain_info, list);
+ return;
+ list_for_each_cookie(head->read_var1, &tomoyo_domain_list) {
+ struct tomoyo_domain_info *domain =
+ list_entry(head->read_var1, typeof(*domain), list);
if (domain->is_deleted)
continue;
done = tomoyo_io_printf(head, "%u %s\n", domain->profile,
break;
}
head->read_eof = done;
- return 0;
}
/**
* The PID is specified by tomoyo_write_pid() so that the user can obtain
* using read()/write() interface rather than sysctl() interface.
*/
-static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
+static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
{
if (head->read_avail == 0 && !head->read_eof) {
const int pid = head->read_step;
domain->domainname->name);
head->read_eof = true;
}
- return 0;
}
+static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
+ [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE]
+ = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN,
+ [TOMOYO_TRANSITION_CONTROL_INITIALIZE]
+ = TOMOYO_KEYWORD_INITIALIZE_DOMAIN,
+ [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN,
+ [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN
+};
+
/**
* tomoyo_write_exception_policy - Write exception policy.
*
{
char *data = head->write_buf;
bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
+ u8 i;
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN))
- return tomoyo_write_domain_keeper_policy(data, false,
- is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN))
- return tomoyo_write_domain_keeper_policy(data, true, is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN))
- return tomoyo_write_domain_initializer_policy(data, false,
- is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN))
- return tomoyo_write_domain_initializer_policy(data, true,
- is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS))
- return tomoyo_write_alias_policy(data, is_delete);
+ for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) {
+ if (tomoyo_str_starts(&data, tomoyo_transition_type[i]))
+ return tomoyo_write_transition_control(data, is_delete,
+ i);
+ }
+ if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR))
+ return tomoyo_write_aggregator_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ))
return tomoyo_write_globally_readable_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN))
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE))
return tomoyo_write_no_rewrite_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP))
- return tomoyo_write_path_group_policy(data, is_delete);
+ return tomoyo_write_group(data, is_delete, TOMOYO_PATH_GROUP);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NUMBER_GROUP))
- return tomoyo_write_number_group_policy(data, is_delete);
+ return tomoyo_write_group(data, is_delete, TOMOYO_NUMBER_GROUP);
return -EINVAL;
}
+static void tomoyo_print_number(char *buffer, int buffer_len,
+ const struct tomoyo_number_union *ptr)
+{
+ int i;
+ unsigned long min = ptr->values[0];
+ const unsigned long max = ptr->values[1];
+ u8 min_type = ptr->min_type;
+ const u8 max_type = ptr->max_type;
+ memset(buffer, 0, buffer_len);
+ buffer_len -= 2;
+ for (i = 0; i < 2; i++) {
+ int len;
+ switch (min_type) {
+ case TOMOYO_VALUE_TYPE_HEXADECIMAL:
+ snprintf(buffer, buffer_len, "0x%lX", min);
+ break;
+ case TOMOYO_VALUE_TYPE_OCTAL:
+ snprintf(buffer, buffer_len, "0%lo", min);
+ break;
+ default:
+ snprintf(buffer, buffer_len, "%lu", min);
+ break;
+ }
+ if (min == max && min_type == max_type)
+ break;
+ len = strlen(buffer);
+ buffer[len++] = '-';
+ buffer += len;
+ buffer_len -= len;
+ min_type = max_type;
+ min = max;
+ }
+}
+
+static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
+ [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP,
+ [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP
+};
+
/**
- * tomoyo_read_exception_policy - Read exception policy.
+ * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
*
* @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx: Index number.
*
- * Returns 0 on success, -EINVAL otherwise.
+ * Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
{
- if (!head->read_eof) {
- switch (head->read_step) {
- case 0:
- head->read_var2 = NULL;
- head->read_step = 1;
- case 1:
- if (!tomoyo_read_domain_keeper_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 2;
- case 2:
- if (!tomoyo_read_globally_readable_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 3;
- case 3:
- head->read_var2 = NULL;
- head->read_step = 4;
- case 4:
- if (!tomoyo_read_domain_initializer_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 5;
- case 5:
- if (!tomoyo_read_alias_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 6;
- case 6:
- head->read_var2 = NULL;
- head->read_step = 7;
- case 7:
- if (!tomoyo_read_file_pattern(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 8;
- case 8:
- if (!tomoyo_read_no_rewrite_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 9;
- case 9:
- if (!tomoyo_read_path_group_policy(head))
- break;
- head->read_var1 = NULL;
- head->read_var2 = NULL;
- head->read_step = 10;
- case 10:
- if (!tomoyo_read_number_group_policy(head))
- break;
- head->read_var1 = NULL;
- head->read_var2 = NULL;
- head->read_step = 11;
- case 11:
- head->read_eof = true;
+ const char *w[3] = { "", "", "" };
+ w[0] = tomoyo_group_name[idx];
+ list_for_each_cookie(head->read_var1, &tomoyo_group_list[idx]) {
+ struct tomoyo_group *group =
+ list_entry(head->read_var1, typeof(*group), list);
+ w[1] = group->group_name->name;
+ list_for_each_cookie(head->read_var2, &group->member_list) {
+ char buffer[128];
+ struct tomoyo_acl_head *ptr =
+ list_entry(head->read_var2, typeof(*ptr), list);
+ if (ptr->is_deleted)
+ continue;
+ if (idx == TOMOYO_PATH_GROUP) {
+ w[2] = container_of(ptr,
+ struct tomoyo_path_group,
+ head)->member_name->name;
+ } else if (idx == TOMOYO_NUMBER_GROUP) {
+ tomoyo_print_number(buffer, sizeof(buffer),
+ &container_of
+ (ptr, struct
+ tomoyo_number_group,
+ head)->number);
+ w[2] = buffer;
+ }
+ if (!tomoyo_io_printf(head, "%s%s %s\n", w[0], w[1],
+ w[2]))
+ return false;
+ }
+ head->read_var2 = NULL;
+ }
+ head->read_var1 = NULL;
+ return true;
+}
+
+/**
+ * tomoyo_read_policy - Read "struct tomoyo_..._entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx: Index number.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
+{
+ list_for_each_cookie(head->read_var2, &tomoyo_policy_list[idx]) {
+ const char *w[4] = { "", "", "", "" };
+ struct tomoyo_acl_head *acl =
+ container_of(head->read_var2, typeof(*acl), list);
+ if (acl->is_deleted)
+ continue;
+ switch (idx) {
+ case TOMOYO_ID_TRANSITION_CONTROL:
+ {
+ struct tomoyo_transition_control *ptr =
+ container_of(acl, typeof(*ptr), head);
+ w[0] = tomoyo_transition_type[ptr->type];
+ if (ptr->program)
+ w[1] = ptr->program->name;
+ if (ptr->domainname)
+ w[3] = ptr->domainname->name;
+ if (w[1][0] && w[3][0])
+ w[2] = " from ";
+ }
+ break;
+ case TOMOYO_ID_GLOBALLY_READABLE:
+ {
+ struct tomoyo_globally_readable_file_entry *ptr
+ = container_of(acl, typeof(*ptr), head);
+ w[0] = TOMOYO_KEYWORD_ALLOW_READ;
+ w[1] = ptr->filename->name;
+ }
+ break;
+ case TOMOYO_ID_AGGREGATOR:
+ {
+ struct tomoyo_aggregator_entry *ptr =
+ container_of(acl, typeof(*ptr), head);
+ w[0] = TOMOYO_KEYWORD_AGGREGATOR;
+ w[1] = ptr->original_name->name;
+ w[2] = " ";
+ w[3] = ptr->aggregated_name->name;
+ }
+ break;
+ case TOMOYO_ID_PATTERN:
+ {
+ struct tomoyo_pattern_entry *ptr =
+ container_of(acl, typeof(*ptr), head);
+ w[0] = TOMOYO_KEYWORD_FILE_PATTERN;
+ w[1] = ptr->pattern->name;
+ }
+ break;
+ case TOMOYO_ID_NO_REWRITE:
+ {
+ struct tomoyo_no_rewrite_entry *ptr =
+ container_of(acl, typeof(*ptr), head);
+ w[0] = TOMOYO_KEYWORD_DENY_REWRITE;
+ w[1] = ptr->pattern->name;
+ }
break;
default:
- return -EINVAL;
+ continue;
}
+ if (!tomoyo_io_printf(head, "%s%s%s%s\n", w[0], w[1], w[2],
+ w[3]))
+ return false;
}
- return 0;
+ head->read_var2 = NULL;
+ return true;
+}
+
+/**
+ * tomoyo_read_exception_policy - Read exception policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static void tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
+{
+ if (head->read_eof)
+ return;
+ while (head->read_step < TOMOYO_MAX_POLICY &&
+ tomoyo_read_policy(head, head->read_step))
+ head->read_step++;
+ if (head->read_step < TOMOYO_MAX_POLICY)
+ return;
+ while (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP &&
+ tomoyo_read_group(head, head->read_step - TOMOYO_MAX_POLICY))
+ head->read_step++;
+ if (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
+ return;
+ head->read_eof = true;
}
/**
* tomoyo_read_query - Read access requests which violated policy in enforcing mode.
*
* @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
*/
-static int tomoyo_read_query(struct tomoyo_io_buffer *head)
+static void tomoyo_read_query(struct tomoyo_io_buffer *head)
{
struct list_head *tmp;
int pos = 0;
int len = 0;
char *buf;
if (head->read_avail)
- return 0;
+ return;
if (head->read_buf) {
kfree(head->read_buf);
head->read_buf = NULL;
spin_unlock(&tomoyo_query_list_lock);
if (!len) {
head->read_step = 0;
- return 0;
+ return;
}
buf = kzalloc(len, GFP_NOFS);
if (!buf)
- return 0;
+ return;
pos = 0;
spin_lock(&tomoyo_query_list_lock);
list_for_each(tmp, &tomoyo_query_list) {
} else {
kfree(buf);
}
- return 0;
}
/**
*
* Returns version information.
*/
-static int tomoyo_read_version(struct tomoyo_io_buffer *head)
+static void 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;
}
/**
*
* Returns the current process's domainname.
*/
-static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
+static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
{
if (!head->read_eof) {
/*
tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
head->read_eof = true;
}
- return 0;
}
/**
if (mutex_lock_interruptible(&head->io_sem))
return -EINTR;
/* Call the policy handler. */
- len = head->read(head);
+ head->read(head);
if (len < 0)
goto out;
/* Write to buffer. */
/* Don't allow updating policies by non manager programs. */
if (head->write != tomoyo_write_pid &&
head->write != tomoyo_write_domain_policy &&
- !tomoyo_is_policy_manager())
+ !tomoyo_policy_manager())
return -EPERM;
if (mutex_lock_interruptible(&head->io_sem))
return -EINTR;
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");
}