diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index bdf1ed7ca45b..811adb5e9fea 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -9,52 +9,73 @@ #include #include #include -#include #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. * @@ -153,44 +174,6 @@ bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) 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. * @@ -198,36 +181,56 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain) * * 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 54db39aa339b..c777c594a00b 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. */ @@ -74,14 +75,6 @@ enum tomoyo_mode_index { #define TOMOYO_VALUE_TYPE_OCTAL 2 #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, @@ -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 a07ca6dc1a08..09ec37c12a9c 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 83fa17a1113a..8e51348d022e 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 7c1c7fdd3681..77ee8bf41948 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 = ""; diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 592b76a2bce8..307793ed6075 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -791,25 +791,67 @@ const char *tomoyo_get_exe(void) return cp; } +/** + * 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. * @@ -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;