diff options
| author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-05-17 10:12:46 +0900 | 
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2010-08-02 15:33:39 +1000 | 
| commit | c3ef1500ec833890275172c7d063333404b64d60 (patch) | |
| tree | 2453368e521a1f7a00098eef06afbedb8404503d /security/tomoyo | |
| parent | 17fcfbd9d45b57f38d40e31f9d28db53f4af5c88 (diff) | |
| download | linux-c3ef1500ec833890275172c7d063333404b64d60.tar.bz2 | |
TOMOYO: Split files into some pieces.
security/tomoyo/common.c became too large to read.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo')
| -rw-r--r-- | security/tomoyo/Makefile | 2 | ||||
| -rw-r--r-- | security/tomoyo/common.c | 1143 | ||||
| -rw-r--r-- | security/tomoyo/common.h | 29 | ||||
| -rw-r--r-- | security/tomoyo/domain.c | 20 | ||||
| -rw-r--r-- | security/tomoyo/file.c | 62 | ||||
| -rw-r--r-- | security/tomoyo/load_policy.c | 81 | ||||
| -rw-r--r-- | security/tomoyo/memory.c | 236 | ||||
| -rw-r--r-- | security/tomoyo/realpath.c | 214 | ||||
| -rw-r--r-- | security/tomoyo/securityfs_if.c | 140 | ||||
| -rw-r--r-- | security/tomoyo/tomoyo.c | 7 | ||||
| -rw-r--r-- | security/tomoyo/util.c | 951 | 
11 files changed, 1469 insertions, 1416 deletions
| diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index d7befab40eff..3aa6f076948e 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile @@ -1 +1 @@ -obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o number_group.o mount.o +obj-y = common.o domain.o file.o gc.o load_policy.o memory.o mount.o number_group.o path_group.o realpath.o securityfs_if.o tomoyo.o util.o diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index ee46aaa3566f..57ddfc5d9c52 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -3,10 +3,7 @@   *   * Common functions for TOMOYO.   * - * Copyright (C) 2005-2009  NTT DATA CORPORATION - * - * Version: 2.2.0   2009/04/01 - * + * Copyright (C) 2005-2010  NTT DATA CORPORATION   */  #include <linux/uaccess.h> @@ -15,12 +12,6 @@  #include <linux/hardirq.h>  #include "common.h" -/* Lock for protecting policy. */ -DEFINE_MUTEX(tomoyo_policy_lock); - -/* Has loading policy done? */ -bool tomoyo_policy_loaded; -  /* String table for functionality that takes 4 modes. */  static const char *tomoyo_mode_4[4] = {  	"disabled", "learning", "permissive", "enforcing" @@ -64,42 +55,6 @@ static bool tomoyo_manage_by_non_root;  /* Utility functions. */ -/* Open operation for /sys/kernel/security/tomoyo/ interface. */ -static int tomoyo_open_control(const u8 type, struct file *file); -/* Close /sys/kernel/security/tomoyo/ interface. */ -static int tomoyo_close_control(struct file *file); -/* Read operation for /sys/kernel/security/tomoyo/ interface. */ -static int tomoyo_read_control(struct file *file, char __user *buffer, -			       const int buffer_len); -/* Write operation for /sys/kernel/security/tomoyo/ interface. */ -static int tomoyo_write_control(struct file *file, const char __user *buffer, -				const int buffer_len); -/* Check whether the domain has too many ACL entries to hold. */ -static bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r); - -/** - * tomoyo_parse_name_union - Parse a tomoyo_name_union. - * - * @filename: Name or name group. - * @ptr:      Pointer to "struct tomoyo_name_union". - * - * Returns true on success, false otherwise. - */ -bool tomoyo_parse_name_union(const char *filename, -			     struct tomoyo_name_union *ptr) -{ -	if (!tomoyo_is_correct_path(filename, 0, 0, 0)) -		return false; -	if (filename[0] == '@') { -		ptr->group = tomoyo_get_path_group(filename + 1); -		ptr->is_group = true; -		return ptr->group != NULL; -	} -	ptr->filename = tomoyo_get_name(filename); -	ptr->is_group = false; -	return ptr->filename != NULL; -} -  /**   * tomoyo_print_name_union - Print a tomoyo_name_union.   * @@ -121,69 +76,6 @@ static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head,  }  /** - * tomoyo_parse_ulong - Parse an "unsigned long" value. - * - * @result: Pointer to "unsigned long". - * @str:    Pointer to string to parse. - * - * Returns value type on success, 0 otherwise. - * - * The @src is updated to point the first character after the value - * on success. - */ -u8 tomoyo_parse_ulong(unsigned long *result, char **str) -{ -	const char *cp = *str; -	char *ep; -	int base = 10; -	if (*cp == '0') { -		char c = *(cp + 1); -		if (c == 'x' || c == 'X') { -			base = 16; -			cp += 2; -		} else if (c >= '0' && c <= '7') { -			base = 8; -			cp++; -		} -	} -	*result = simple_strtoul(cp, &ep, base); -	if (cp == ep) -		return 0; -	*str = ep; -	switch (base) { -	case 16: -		return TOMOYO_VALUE_TYPE_HEXADECIMAL; -	case 8: -		return TOMOYO_VALUE_TYPE_OCTAL; -	default: -		return TOMOYO_VALUE_TYPE_DECIMAL; -	} -} - -/** - * tomoyo_print_ulong - Print an "unsigned long" value. - * - * @buffer:     Pointer to buffer. - * @buffer_len: Size of @buffer. - * @value:      An "unsigned long" value. - * @type:       Type of @value. - * - * Returns nothing. - */ -void tomoyo_print_ulong(char *buffer, const int buffer_len, -			const unsigned long value, const u8 type) -{ -	if (type == TOMOYO_VALUE_TYPE_DECIMAL) -		snprintf(buffer, buffer_len, "%lu", value); -	else if (type == TOMOYO_VALUE_TYPE_OCTAL) -		snprintf(buffer, buffer_len, "0%lo", value); -	else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL) -		snprintf(buffer, buffer_len, "0x%lX", value); -	else -		snprintf(buffer, buffer_len, "type(%u)", type); -} - -/**   * tomoyo_print_number_union - Print a tomoyo_number_union.   *   * @head:       Pointer to "struct tomoyo_io_buffer". @@ -234,704 +126,6 @@ bool tomoyo_print_number_union(struct tomoyo_io_buffer *head,  }  /** - * tomoyo_parse_number_union - Parse a tomoyo_number_union. - * - * @data: Number or number range or number group. - * @ptr:  Pointer to "struct tomoyo_number_union". - * - * Returns true on success, false otherwise. - */ -bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num) -{ -	u8 type; -	unsigned long v; -	memset(num, 0, sizeof(*num)); -	if (data[0] == '@') { -		if (!tomoyo_is_correct_path(data, 0, 0, 0)) -			return false; -		num->group = tomoyo_get_number_group(data + 1); -		num->is_group = true; -		return num->group != NULL; -	} -	type = tomoyo_parse_ulong(&v, &data); -	if (!type) -		return false; -	num->values[0] = v; -	num->min_type = type; -	if (!*data) { -		num->values[1] = v; -		num->max_type = type; -		return true; -	} -	if (*data++ != '-') -		return false; -	type = tomoyo_parse_ulong(&v, &data); -	if (!type || *data) -		return false; -	num->values[1] = v; -	num->max_type = type; -	return true; -} - -/** - * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. - * - * @str: Pointer to the string. - * - * Returns true if @str is a \ooo style octal value, false otherwise. - * - * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. - * This function verifies that \ooo is in valid range. - */ -static inline bool tomoyo_is_byte_range(const char *str) -{ -	return *str >= '0' && *str++ <= '3' && -		*str >= '0' && *str++ <= '7' && -		*str >= '0' && *str <= '7'; -} - -/** - * tomoyo_is_alphabet_char - Check whether the character is an alphabet. - * - * @c: The character to check. - * - * Returns true if @c is an alphabet character, false otherwise. - */ -static inline bool tomoyo_is_alphabet_char(const char c) -{ -	return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); -} - -/** - * tomoyo_make_byte - Make byte value from three octal characters. - * - * @c1: The first character. - * @c2: The second character. - * @c3: The third character. - * - * Returns byte value. - */ -static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) -{ -	return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); -} - -/** - * tomoyo_str_starts - Check whether the given string starts with the given keyword. - * - * @src:  Pointer to pointer to the string. - * @find: Pointer to the keyword. - * - * Returns true if @src starts with @find, false otherwise. - * - * The @src is updated to point the first character after the @find - * if @src starts with @find. - */ -static bool tomoyo_str_starts(char **src, const char *find) -{ -	const int len = strlen(find); -	char *tmp = *src; - -	if (strncmp(tmp, find, len)) -		return false; -	tmp += len; -	*src = tmp; -	return true; -} - -/** - * tomoyo_normalize_line - Format string. - * - * @buffer: The line to normalize. - * - * Leading and trailing whitespaces are removed. - * Multiple whitespaces are packed into single space. - * - * Returns nothing. - */ -static void tomoyo_normalize_line(unsigned char *buffer) -{ -	unsigned char *sp = buffer; -	unsigned char *dp = buffer; -	bool first = true; - -	while (tomoyo_is_invalid(*sp)) -		sp++; -	while (*sp) { -		if (!first) -			*dp++ = ' '; -		first = false; -		while (tomoyo_is_valid(*sp)) -			*dp++ = *sp++; -		while (tomoyo_is_invalid(*sp)) -			sp++; -	} -	*dp = '\0'; -} - -/** - * tomoyo_tokenize - Tokenize string. - * - * @buffer: The line to tokenize. - * @w:      Pointer to "char *". - * @size:   Sizeof @w . - * - * Returns true on success, false otherwise. - */ -bool tomoyo_tokenize(char *buffer, char *w[], size_t size) -{ -	int count = size / sizeof(char *); -	int i; -	for (i = 0; i < count; i++) -		w[i] = ""; -	for (i = 0; i < count; i++) { -		char *cp = strchr(buffer, ' '); -		if (cp) -			*cp = '\0'; -		w[i] = buffer; -		if (!cp) -			break; -		buffer = cp + 1; -	} -	return i < count || !*buffer; -} - -/** - * tomoyo_is_correct_path - Validate a pathname. - * @filename:     The pathname to check. - * @start_type:   Should the pathname start with '/'? - *                1 = must / -1 = must not / 0 = don't care - * @pattern_type: Can the pathname contain a wildcard? - *                1 = must / -1 = must not / 0 = don't care - * @end_type:     Should the pathname end with '/'? - *                1 = must / -1 = must not / 0 = don't care - * - * Check whether the given filename follows the naming rules. - * Returns true if @filename follows the naming rules, false otherwise. - */ -bool tomoyo_is_correct_path(const char *filename, const s8 start_type, -			    const s8 pattern_type, const s8 end_type) -{ -	const char *const start = filename; -	bool in_repetition = false; -	bool contains_pattern = false; -	unsigned char c; -	unsigned char d; -	unsigned char e; - -	if (!filename) -		goto out; -	c = *filename; -	if (start_type == 1) { /* Must start with '/' */ -		if (c != '/') -			goto out; -	} else if (start_type == -1) { /* Must not start with '/' */ -		if (c == '/') -			goto out; -	} -	if (c) -		c = *(filename + strlen(filename) - 1); -	if (end_type == 1) { /* Must end with '/' */ -		if (c != '/') -			goto out; -	} else if (end_type == -1) { /* Must not end with '/' */ -		if (c == '/') -			goto out; -	} -	while (1) { -		c = *filename++; -		if (!c) -			break; -		if (c == '\\') { -			c = *filename++; -			switch (c) { -			case '\\':  /* "\\" */ -				continue; -			case '$':   /* "\$" */ -			case '+':   /* "\+" */ -			case '?':   /* "\?" */ -			case '*':   /* "\*" */ -			case '@':   /* "\@" */ -			case 'x':   /* "\x" */ -			case 'X':   /* "\X" */ -			case 'a':   /* "\a" */ -			case 'A':   /* "\A" */ -			case '-':   /* "\-" */ -				if (pattern_type == -1) -					break; /* Must not contain pattern */ -				contains_pattern = true; -				continue; -			case '{':   /* "/\{" */ -				if (filename - 3 < start || -				    *(filename - 3) != '/') -					break; -				if (pattern_type == -1) -					break; /* Must not contain pattern */ -				contains_pattern = true; -				in_repetition = true; -				continue; -			case '}':   /* "\}/" */ -				if (*filename != '/') -					break; -				if (!in_repetition) -					break; -				in_repetition = false; -				continue; -			case '0':   /* "\ooo" */ -			case '1': -			case '2': -			case '3': -				d = *filename++; -				if (d < '0' || d > '7') -					break; -				e = *filename++; -				if (e < '0' || e > '7') -					break; -				c = tomoyo_make_byte(c, d, e); -				if (tomoyo_is_invalid(c)) -					continue; /* pattern is not \000 */ -			} -			goto out; -		} else if (in_repetition && c == '/') { -			goto out; -		} else if (tomoyo_is_invalid(c)) { -			goto out; -		} -	} -	if (pattern_type == 1) { /* Must contain pattern */ -		if (!contains_pattern) -			goto out; -	} -	if (in_repetition) -		goto out; -	return true; - out: -	return false; -} - -/** - * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. - * @domainname:   The domainname to check. - * - * Returns true if @domainname follows the naming rules, false otherwise. - */ -bool tomoyo_is_correct_domain(const unsigned char *domainname) -{ -	unsigned char c; -	unsigned char d; -	unsigned char e; - -	if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, -				   TOMOYO_ROOT_NAME_LEN)) -		goto out; -	domainname += TOMOYO_ROOT_NAME_LEN; -	if (!*domainname) -		return true; -	do { -		if (*domainname++ != ' ') -			goto out; -		if (*domainname++ != '/') -			goto out; -		while ((c = *domainname) != '\0' && c != ' ') { -			domainname++; -			if (c == '\\') { -				c = *domainname++; -				switch ((c)) { -				case '\\':  /* "\\" */ -					continue; -				case '0':   /* "\ooo" */ -				case '1': -				case '2': -				case '3': -					d = *domainname++; -					if (d < '0' || d > '7') -						break; -					e = *domainname++; -					if (e < '0' || e > '7') -						break; -					c = tomoyo_make_byte(c, d, e); -					if (tomoyo_is_invalid(c)) -						/* pattern is not \000 */ -						continue; -				} -				goto out; -			} else if (tomoyo_is_invalid(c)) { -				goto out; -			} -		} -	} while (*domainname); -	return true; - out: -	return false; -} - -/** - * tomoyo_is_domain_def - Check whether the given token can be a domainname. - * - * @buffer: The token to check. - * - * Returns true if @buffer possibly be a domainname, false otherwise. - */ -bool tomoyo_is_domain_def(const unsigned char *buffer) -{ -	return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN); -} - -/** - * tomoyo_find_domain - Find a domain by the given name. - * - * @domainname: The domainname to find. - * - * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) -{ -	struct tomoyo_domain_info *domain; -	struct tomoyo_path_info name; - -	name.name = domainname; -	tomoyo_fill_path_info(&name); -	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { -		if (!domain->is_deleted && -		    !tomoyo_pathcmp(&name, domain->domainname)) -			return domain; -	} -	return NULL; -} - -/** - * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. - * - * @filename: The string to evaluate. - * - * Returns the initial length without a pattern in @filename. - */ -static int tomoyo_const_part_length(const char *filename) -{ -	char c; -	int len = 0; - -	if (!filename) -		return 0; -	while ((c = *filename++) != '\0') { -		if (c != '\\') { -			len++; -			continue; -		} -		c = *filename++; -		switch (c) { -		case '\\':  /* "\\" */ -			len += 2; -			continue; -		case '0':   /* "\ooo" */ -		case '1': -		case '2': -		case '3': -			c = *filename++; -			if (c < '0' || c > '7') -				break; -			c = *filename++; -			if (c < '0' || c > '7') -				break; -			len += 4; -			continue; -		} -		break; -	} -	return len; -} - -/** - * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. - * - * @ptr: Pointer to "struct tomoyo_path_info" to fill in. - * - * The caller sets "struct tomoyo_path_info"->name. - */ -void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) -{ -	const char *name = ptr->name; -	const int len = strlen(name); - -	ptr->const_len = tomoyo_const_part_length(name); -	ptr->is_dir = len && (name[len - 1] == '/'); -	ptr->is_patterned = (ptr->const_len < len); -	ptr->hash = full_name_hash(name, len); -} - -/** - * tomoyo_file_matches_pattern2 - Pattern matching without '/' character - * and "\-" pattern. - * - * @filename:     The start of string to check. - * @filename_end: The end of string to check. - * @pattern:      The start of pattern to compare. - * @pattern_end:  The end of pattern to compare. - * - * Returns true if @filename matches @pattern, false otherwise. - */ -static bool tomoyo_file_matches_pattern2(const char *filename, -					 const char *filename_end, -					 const char *pattern, -					 const char *pattern_end) -{ -	while (filename < filename_end && pattern < pattern_end) { -		char c; -		if (*pattern != '\\') { -			if (*filename++ != *pattern++) -				return false; -			continue; -		} -		c = *filename; -		pattern++; -		switch (*pattern) { -			int i; -			int j; -		case '?': -			if (c == '/') { -				return false; -			} else if (c == '\\') { -				if (filename[1] == '\\') -					filename++; -				else if (tomoyo_is_byte_range(filename + 1)) -					filename += 3; -				else -					return false; -			} -			break; -		case '\\': -			if (c != '\\') -				return false; -			if (*++filename != '\\') -				return false; -			break; -		case '+': -			if (!isdigit(c)) -				return false; -			break; -		case 'x': -			if (!isxdigit(c)) -				return false; -			break; -		case 'a': -			if (!tomoyo_is_alphabet_char(c)) -				return false; -			break; -		case '0': -		case '1': -		case '2': -		case '3': -			if (c == '\\' && tomoyo_is_byte_range(filename + 1) -			    && strncmp(filename + 1, pattern, 3) == 0) { -				filename += 3; -				pattern += 2; -				break; -			} -			return false; /* Not matched. */ -		case '*': -		case '@': -			for (i = 0; i <= filename_end - filename; i++) { -				if (tomoyo_file_matches_pattern2( -						    filename + i, filename_end, -						    pattern + 1, pattern_end)) -					return true; -				c = filename[i]; -				if (c == '.' && *pattern == '@') -					break; -				if (c != '\\') -					continue; -				if (filename[i + 1] == '\\') -					i++; -				else if (tomoyo_is_byte_range(filename + i + 1)) -					i += 3; -				else -					break; /* Bad pattern. */ -			} -			return false; /* Not matched. */ -		default: -			j = 0; -			c = *pattern; -			if (c == '$') { -				while (isdigit(filename[j])) -					j++; -			} else if (c == 'X') { -				while (isxdigit(filename[j])) -					j++; -			} else if (c == 'A') { -				while (tomoyo_is_alphabet_char(filename[j])) -					j++; -			} -			for (i = 1; i <= j; i++) { -				if (tomoyo_file_matches_pattern2( -						    filename + i, filename_end, -						    pattern + 1, pattern_end)) -					return true; -			} -			return false; /* Not matched or bad pattern. */ -		} -		filename++; -		pattern++; -	} -	while (*pattern == '\\' && -	       (*(pattern + 1) == '*' || *(pattern + 1) == '@')) -		pattern += 2; -	return filename == filename_end && pattern == pattern_end; -} - -/** - * tomoyo_file_matches_pattern - Pattern matching without without '/' character. - * - * @filename:     The start of string to check. - * @filename_end: The end of string to check. - * @pattern:      The start of pattern to compare. - * @pattern_end:  The end of pattern to compare. - * - * Returns true if @filename matches @pattern, false otherwise. - */ -static bool tomoyo_file_matches_pattern(const char *filename, -					   const char *filename_end, -					   const char *pattern, -					   const char *pattern_end) -{ -	const char *pattern_start = pattern; -	bool first = true; -	bool result; - -	while (pattern < pattern_end - 1) { -		/* Split at "\-" pattern. */ -		if (*pattern++ != '\\' || *pattern++ != '-') -			continue; -		result = tomoyo_file_matches_pattern2(filename, -						      filename_end, -						      pattern_start, -						      pattern - 2); -		if (first) -			result = !result; -		if (result) -			return false; -		first = false; -		pattern_start = pattern; -	} -	result = tomoyo_file_matches_pattern2(filename, filename_end, -					      pattern_start, pattern_end); -	return first ? result : !result; -} - -/** - * tomoyo_path_matches_pattern2 - Do pathname pattern matching. - * - * @f: The start of string to check. - * @p: The start of pattern to compare. - * - * Returns true if @f matches @p, false otherwise. - */ -static bool tomoyo_path_matches_pattern2(const char *f, const char *p) -{ -	const char *f_delimiter; -	const char *p_delimiter; - -	while (*f && *p) { -		f_delimiter = strchr(f, '/'); -		if (!f_delimiter) -			f_delimiter = f + strlen(f); -		p_delimiter = strchr(p, '/'); -		if (!p_delimiter) -			p_delimiter = p + strlen(p); -		if (*p == '\\' && *(p + 1) == '{') -			goto recursive; -		if (!tomoyo_file_matches_pattern(f, f_delimiter, p, -						 p_delimiter)) -			return false; -		f = f_delimiter; -		if (*f) -			f++; -		p = p_delimiter; -		if (*p) -			p++; -	} -	/* Ignore trailing "\*" and "\@" in @pattern. */ -	while (*p == '\\' && -	       (*(p + 1) == '*' || *(p + 1) == '@')) -		p += 2; -	return !*f && !*p; - recursive: -	/* -	 * The "\{" pattern is permitted only after '/' character. -	 * This guarantees that below "*(p - 1)" is safe. -	 * Also, the "\}" pattern is permitted only before '/' character -	 * so that "\{" + "\}" pair will not break the "\-" operator. -	 */ -	if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || -	    *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') -		return false; /* Bad pattern. */ -	do { -		/* Compare current component with pattern. */ -		if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, -						 p_delimiter - 2)) -			break; -		/* Proceed to next component. */ -		f = f_delimiter; -		if (!*f) -			break; -		f++; -		/* Continue comparison. */ -		if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) -			return true; -		f_delimiter = strchr(f, '/'); -	} while (f_delimiter); -	return false; /* Not matched. */ -} - -/** - * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. - * - * @filename: The filename to check. - * @pattern:  The pattern to compare. - * - * Returns true if matches, false otherwise. - * - * The following patterns are available. - *   \\     \ itself. - *   \ooo   Octal representation of a byte. - *   \*     Zero or more repetitions of characters other than '/'. - *   \@     Zero or more repetitions of characters other than '/' or '.'. - *   \?     1 byte character other than '/'. - *   \$     One or more repetitions of decimal digits. - *   \+     1 decimal digit. - *   \X     One or more repetitions of hexadecimal digits. - *   \x     1 hexadecimal digit. - *   \A     One or more repetitions of alphabet characters. - *   \a     1 alphabet character. - * - *   \-     Subtraction operator. - * - *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ - *               /dir/dir/dir/ ). - */ -bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, -				 const struct tomoyo_path_info *pattern) -{ -	const char *f = filename->name; -	const char *p = pattern->name; -	const int len = pattern->const_len; - -	/* If @pattern doesn't contain pattern, I can use strcmp(). */ -	if (!pattern->is_patterned) -		return !tomoyo_pathcmp(filename, pattern); -	/* Don't compare directory and non-directory. */ -	if (filename->is_dir != pattern->is_dir) -		return false; -	/* Compare the initial length without patterns. */ -	if (strncmp(f, p, len)) -		return false; -	f += len; -	p += len; -	return tomoyo_path_matches_pattern2(f, p); -} - -/**   * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure.   *   * @head: Pointer to "struct tomoyo_io_buffer". @@ -960,33 +154,6 @@ bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)  }  /** - * tomoyo_get_exe - Get tomoyo_realpath() of current process. - * - * Returns the tomoyo_realpath() of current process on success, NULL otherwise. - * - * This function uses kzalloc(), so the caller must call kfree() - * if this function didn't return NULL. - */ -static const char *tomoyo_get_exe(void) -{ -	struct mm_struct *mm = current->mm; -	struct vm_area_struct *vma; -	const char *cp = NULL; - -	if (!mm) -		return NULL; -	down_read(&mm->mmap_sem); -	for (vma = mm->mmap; vma; vma = vma->vm_next) { -		if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { -			cp = tomoyo_realpath_from_path(&vma->vm_file->f_path); -			break; -		} -	} -	up_read(&mm->mmap_sem); -	return cp; -} - -/**   * tomoyo_check_flags - Check mode for specified functionality.   *   * @domain: Pointer to "struct tomoyo_domain_info". @@ -1025,76 +192,6 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)  }  /** - * tomoyo_domain_quota_is_ok - Check for domain's quota. - * - * @r: Pointer to "struct tomoyo_request_info". - * - * Returns true if the domain is not exceeded quota, false otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -static bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) -{ -	unsigned int count = 0; -	struct tomoyo_domain_info *domain = r->domain; -	struct tomoyo_acl_info *ptr; - -	if (r->mode != TOMOYO_CONFIG_LEARNING) -		return false; -	if (!domain) -		return true; -	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { -		switch (ptr->type) { -			u16 perm; -			u8 i; -		case TOMOYO_TYPE_PATH_ACL: -			perm = container_of(ptr, struct tomoyo_path_acl, head) -				->perm; -			for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++) -				if (perm & (1 << i)) -					count++; -			if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) -				count -= 2; -			break; -		case TOMOYO_TYPE_PATH2_ACL: -			perm = container_of(ptr, struct tomoyo_path2_acl, head) -				->perm; -			for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++) -				if (perm & (1 << i)) -					count++; -			break; -		case TOMOYO_TYPE_PATH_NUMBER_ACL: -			perm = container_of(ptr, struct tomoyo_path_number_acl, -					    head)->perm; -			for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++) -				if (perm & (1 << i)) -					count++; -			break; -		case TOMOYO_TYPE_PATH_NUMBER3_ACL: -			perm = container_of(ptr, struct tomoyo_path_number3_acl, -					    head)->perm; -			for (i = 0; i < TOMOYO_MAX_PATH_NUMBER3_OPERATION; i++) -				if (perm & (1 << i)) -					count++; -			break; -		case TOMOYO_TYPE_MOUNT_ACL: -			if (!container_of(ptr, struct tomoyo_mount_acl, head)-> -			    is_deleted) -				count++; -		} -	} -	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) -		return true; -	if (!domain->quota_warned) { -		domain->quota_warned = true; -		printk(KERN_WARNING "TOMOYO-WARNING: " -		       "Domain '%s' has so many ACLs to hold. " -		       "Stopped learning mode.\n", domain->domainname->name); -	} -	return false; -} - -/**   * tomoyo_find_or_assign_new_profile - Create a new profile.   *   * @profile: Profile number to create. @@ -2118,91 +1215,6 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)  	return 0;  } -/* path to policy loader */ -static const char *tomoyo_loader = "/sbin/tomoyo-init"; - -/** - * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. - * - * Returns true if /sbin/tomoyo-init exists, false otherwise. - */ -static bool tomoyo_policy_loader_exists(void) -{ -	/* -	 * Don't activate MAC if the policy loader doesn't exist. -	 * If the initrd includes /sbin/init but real-root-dev has not -	 * mounted on / yet, activating MAC will block the system since -	 * policies are not loaded yet. -	 * Thus, let do_execve() call this function everytime. -	 */ -	struct path path; - -	if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { -		printk(KERN_INFO "Not activating Mandatory Access Control now " -		       "since %s doesn't exist.\n", tomoyo_loader); -		return false; -	} -	path_put(&path); -	return true; -} - -/** - * tomoyo_load_policy - Run external policy loader to load policy. - * - * @filename: The program about to start. - * - * This function checks whether @filename is /sbin/init , and if so - * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init - * and then continues invocation of /sbin/init. - * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and - * writes to /sys/kernel/security/tomoyo/ interfaces. - * - * Returns nothing. - */ -void tomoyo_load_policy(const char *filename) -{ -	char *argv[2]; -	char *envp[3]; - -	if (tomoyo_policy_loaded) -		return; -	/* -	 * Check filename is /sbin/init or /sbin/tomoyo-start. -	 * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't -	 * be passed. -	 * You can create /sbin/tomoyo-start by -	 * "ln -s /bin/true /sbin/tomoyo-start". -	 */ -	if (strcmp(filename, "/sbin/init") && -	    strcmp(filename, "/sbin/tomoyo-start")) -		return; -	if (!tomoyo_policy_loader_exists()) -		return; - -	printk(KERN_INFO "Calling %s to load policy. Please wait.\n", -	       tomoyo_loader); -	argv[0] = (char *) tomoyo_loader; -	argv[1] = NULL; -	envp[0] = "HOME=/"; -	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; -	envp[2] = NULL; -	call_usermodehelper(argv[0], argv, envp, 1); - -	printk(KERN_INFO "TOMOYO: 2.2.0   2009/04/01\n"); -	printk(KERN_INFO "Mandatory Access Control activated.\n"); -	tomoyo_policy_loaded = true; -	{ /* Check all profiles currently assigned to domains are defined. */ -		struct tomoyo_domain_info *domain; -		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { -			const u8 profile = domain->profile; -			if (tomoyo_profile_ptr[profile]) -				continue; -			panic("Profile %u (used by '%s') not defined.\n", -			      profile, domain->domainname->name); -		} -	} -} -  /**   * tomoyo_print_header - Get header line of audit log.   * @@ -2601,7 +1613,7 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)   *   * Caller acquires tomoyo_read_lock().   */ -static int tomoyo_open_control(const u8 type, struct file *file) +int tomoyo_open_control(const u8 type, struct file *file)  {  	struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); @@ -2744,8 +1756,8 @@ int tomoyo_poll_control(struct file *file, poll_table *wait)   *   * Caller holds tomoyo_read_lock().   */ -static int tomoyo_read_control(struct file *file, char __user *buffer, -			       const int buffer_len) +int tomoyo_read_control(struct file *file, char __user *buffer, +			const int buffer_len)  {  	int len = 0;  	struct tomoyo_io_buffer *head = file->private_data; @@ -2789,8 +1801,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer,   *   * Caller holds tomoyo_read_lock().   */ -static int tomoyo_write_control(struct file *file, const char __user *buffer, -				const int buffer_len) +int tomoyo_write_control(struct file *file, const char __user *buffer, +			 const int buffer_len)  {  	struct tomoyo_io_buffer *head = file->private_data;  	int error = buffer_len; @@ -2841,7 +1853,7 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,   *   * Caller looses tomoyo_read_lock().   */ -static int tomoyo_close_control(struct file *file) +int tomoyo_close_control(struct file *file)  {  	struct tomoyo_io_buffer *head = file->private_data;  	const bool is_write = !!head->write_buf; @@ -2868,131 +1880,22 @@ static int tomoyo_close_control(struct file *file)  }  /** - * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. - * - * @inode: Pointer to "struct inode". - * @file:  Pointer to "struct file". - * - * Returns 0 on success, negative value otherwise. + * tomoyo_check_profile - Check all profiles currently assigned to domains are defined.   */ -static int tomoyo_open(struct inode *inode, struct file *file) +void tomoyo_check_profile(void)  { -	const int key = ((u8 *) file->f_path.dentry->d_inode->i_private) -		- ((u8 *) NULL); -	return tomoyo_open_control(key, file); -} - -/** - * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. - * - * @inode: Pointer to "struct inode". - * @file:  Pointer to "struct file". - * - * Returns 0 on success, negative value otherwise. - */ -static int tomoyo_release(struct inode *inode, struct file *file) -{ -	return tomoyo_close_control(file); -} - -/** - * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. - * - * @file:  Pointer to "struct file". - * @buf:   Pointer to buffer. - * @count: Size of @buf. - * @ppos:  Unused. - * - * Returns bytes read on success, negative value otherwise. - */ -static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, -			   loff_t *ppos) -{ -	return tomoyo_read_control(file, buf, count); -} - -/** - * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. - * - * @file:  Pointer to "struct file". - * @buf:   Pointer to buffer. - * @count: Size of @buf. - * @ppos:  Unused. - * - * Returns @count on success, negative value otherwise. - */ -static ssize_t tomoyo_write(struct file *file, const char __user *buf, -			    size_t count, loff_t *ppos) -{ -	return tomoyo_write_control(file, buf, count); -} - -/* - * tomoyo_operations is a "struct file_operations" which is used for handling - * /sys/kernel/security/tomoyo/ interface. - * - * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). - * See tomoyo_io_buffer for internals. - */ -static const struct file_operations tomoyo_operations = { -	.open    = tomoyo_open, -	.release = tomoyo_release, -	.read    = tomoyo_read, -	.write   = tomoyo_write, -}; - -/** - * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. - * - * @name:   The name of the interface file. - * @mode:   The permission of the interface file. - * @parent: The parent directory. - * @key:    Type of interface. - * - * Returns nothing. - */ -static void __init tomoyo_create_entry(const char *name, const mode_t mode, -				       struct dentry *parent, const u8 key) -{ -	securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key, -			       &tomoyo_operations); -} - -/** - * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. - * - * Returns 0. - */ -static int __init tomoyo_initerface_init(void) -{ -	struct dentry *tomoyo_dir; - -	/* Don't create securityfs entries unless registered. */ -	if (current_cred()->security != &tomoyo_kernel_domain) -		return 0; - -	tomoyo_dir = securityfs_create_dir("tomoyo", NULL); -	tomoyo_create_entry("query",            0600, tomoyo_dir, -			    TOMOYO_QUERY); -	tomoyo_create_entry("domain_policy",    0600, tomoyo_dir, -			    TOMOYO_DOMAINPOLICY); -	tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, -			    TOMOYO_EXCEPTIONPOLICY); -	tomoyo_create_entry("self_domain",      0400, tomoyo_dir, -			    TOMOYO_SELFDOMAIN); -	tomoyo_create_entry(".domain_status",   0600, tomoyo_dir, -			    TOMOYO_DOMAIN_STATUS); -	tomoyo_create_entry(".process_status",  0600, tomoyo_dir, -			    TOMOYO_PROCESS_STATUS); -	tomoyo_create_entry("meminfo",          0600, tomoyo_dir, -			    TOMOYO_MEMINFO); -	tomoyo_create_entry("profile",          0600, tomoyo_dir, -			    TOMOYO_PROFILE); -	tomoyo_create_entry("manager",          0600, tomoyo_dir, -			    TOMOYO_MANAGER); -	tomoyo_create_entry("version",          0400, tomoyo_dir, -			    TOMOYO_VERSION); -	return 0; +	struct tomoyo_domain_info *domain; +	const int idx = tomoyo_read_lock(); +	tomoyo_policy_loaded = true; +	/* Check all profiles currently assigned to domains are defined. */ +	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { +		const u8 profile = domain->profile; +		if (tomoyo_profile_ptr[profile]) +			continue; +		panic("Profile %u (used by '%s') not defined.\n", +		      profile, domain->domainname->name); +	} +	tomoyo_read_unlock(idx); +	printk(KERN_INFO "TOMOYO: 2.2.0   2009/04/01\n"); +	printk(KERN_INFO "Mandatory Access Control activated.\n");  } - -fs_initcall(tomoyo_initerface_init); diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index dc5f98f52f61..be03e4a21db0 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -673,6 +673,31 @@ struct tomoyo_policy_manager_entry {  extern asmlinkage long sys_getpid(void);  extern asmlinkage long sys_getppid(void); +/* Check whether the given string starts with the given keyword. */ +bool tomoyo_str_starts(char **src, const char *find); +/* Get tomoyo_realpath() of current process. */ +const char *tomoyo_get_exe(void); +/* Format string. */ +void tomoyo_normalize_line(unsigned char *buffer); +/* Print warning or error message on console. */ +void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) +     __attribute__ ((format(printf, 2, 3))); +/* Check all profiles currently assigned to domains are defined. */ +void tomoyo_check_profile(void); +/* Open operation for /sys/kernel/security/tomoyo/ interface. */ +int tomoyo_open_control(const u8 type, struct file *file); +/* Close /sys/kernel/security/tomoyo/ interface. */ +int tomoyo_close_control(struct file *file); +/* Read operation for /sys/kernel/security/tomoyo/ interface. */ +int tomoyo_read_control(struct file *file, char __user *buffer, +			const int buffer_len); +/* Write operation for /sys/kernel/security/tomoyo/ interface. */ +int tomoyo_write_control(struct file *file, const char __user *buffer, +			 const int buffer_len); +/* Check whether the domain has too many ACL entries to hold. */ +bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r); +/* Print out of memory warning message. */ +void tomoyo_warn_oom(const char *function);  /* Check whether the given name matches the given name_union. */  bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,  			       const struct tomoyo_name_union *ptr); @@ -837,8 +862,8 @@ int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);  /* Set memory quota. */  int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); -/* Initialize realpath related code. */ -void __init tomoyo_realpath_init(void); +/* Initialize mm related code. */ +void __init tomoyo_mm_init(void);  int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,  			   const struct tomoyo_path_info *filename);  int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 7e242d27da5a..08428bc082df 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -1,12 +1,9 @@  /*   * security/tomoyo/domain.c   * - * Implementation of the Domain-Based Mandatory Access Control. - * - * Copyright (C) 2005-2009  NTT DATA CORPORATION - * - * Version: 2.2.0   2009/04/01 + * Domain transition functions for TOMOYO.   * + * Copyright (C) 2005-2010  NTT DATA CORPORATION   */  #include "common.h" @@ -697,24 +694,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)  	struct tomoyo_path_info rn; /* real name */  	struct tomoyo_path_info sn; /* symlink name */  	struct tomoyo_path_info ln; /* last name */ -	static bool initialized;  	tomoyo_init_request_info(&r, NULL);  	if (!tmp)  		goto out; -	if (!initialized) { -		/* -		 * Built-in initializers. This is needed because policies are -		 * not loaded until starting /sbin/init. -		 */ -		tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug", -						       false, false); -		tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe", -						       false, false); -		initialized = true; -	} -   retry:  	/* Get tomoyo_realpath of program. */  	retval = -ENOENT; diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index c629cb4e2c66..c13806937dc6 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -1,12 +1,9 @@  /*   * security/tomoyo/file.c   * - * Implementation of the Domain-Based Mandatory Access Control. - * - * Copyright (C) 2005-2009  NTT DATA CORPORATION - * - * Version: 2.2.0   2009/04/01 + * Pathname restriction functions.   * + * Copyright (C) 2005-2010  NTT DATA CORPORATION   */  #include "common.h" @@ -100,61 +97,6 @@ bool tomoyo_compare_number_union(const unsigned long value,  }  /** - * 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(). - * - * Returns mode. - */ -int tomoyo_init_request_info(struct tomoyo_request_info *r, -			     struct tomoyo_domain_info *domain) -{ -	memset(r, 0, sizeof(*r)); -	if (!domain) -		domain = tomoyo_domain(); -	r->domain = domain; -	r->mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); -	return r->mode; -} - -static void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...) -     __attribute__ ((format(printf, 2, 3))); -/** - * tomoyo_warn_log - Print warning or error message on console. - * - * @r:   Pointer to "struct tomoyo_request_info". - * @fmt: The printf()'s format string, followed by parameters. - */ -static 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) -			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); -	} -	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)); -	kfree(buffer); -} - -/**   * tomoyo_path2keyword - Get the name of single path operation.   *   * @operation: Type of operation. diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c new file mode 100644 index 000000000000..bbada7ca1b91 --- /dev/null +++ b/security/tomoyo/load_policy.c @@ -0,0 +1,81 @@ +/* + * security/tomoyo/load_policy.c + * + * Policy loader launcher for TOMOYO. + * + * Copyright (C) 2005-2010  NTT DATA CORPORATION + */ + +#include "common.h" + +/* path to policy loader */ +static const char *tomoyo_loader = "/sbin/tomoyo-init"; + +/** + * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists. + * + * Returns true if /sbin/tomoyo-init exists, false otherwise. + */ +static bool tomoyo_policy_loader_exists(void) +{ +	/* +	 * Don't activate MAC if the policy loader doesn't exist. +	 * If the initrd includes /sbin/init but real-root-dev has not +	 * mounted on / yet, activating MAC will block the system since +	 * policies are not loaded yet. +	 * Thus, let do_execve() call this function everytime. +	 */ +	struct path path; + +	if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) { +		printk(KERN_INFO "Not activating Mandatory Access Control now " +		       "since %s doesn't exist.\n", tomoyo_loader); +		return false; +	} +	path_put(&path); +	return true; +} + +/** + * tomoyo_load_policy - Run external policy loader to load policy. + * + * @filename: The program about to start. + * + * This function checks whether @filename is /sbin/init , and if so + * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init + * and then continues invocation of /sbin/init. + * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and + * writes to /sys/kernel/security/tomoyo/ interfaces. + * + * Returns nothing. + */ +void tomoyo_load_policy(const char *filename) +{ +	char *argv[2]; +	char *envp[3]; + +	if (tomoyo_policy_loaded) +		return; +	/* +	 * Check filename is /sbin/init or /sbin/tomoyo-start. +	 * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't +	 * be passed. +	 * You can create /sbin/tomoyo-start by +	 * "ln -s /bin/true /sbin/tomoyo-start". +	 */ +	if (strcmp(filename, "/sbin/init") && +	    strcmp(filename, "/sbin/tomoyo-start")) +		return; +	if (!tomoyo_policy_loader_exists()) +		return; + +	printk(KERN_INFO "Calling %s to load policy. Please wait.\n", +	       tomoyo_loader); +	argv[0] = (char *) tomoyo_loader; +	argv[1] = NULL; +	envp[0] = "HOME=/"; +	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; +	envp[2] = NULL; +	call_usermodehelper(argv[0], argv, envp, 1); +	tomoyo_check_profile(); +} diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c new file mode 100644 index 000000000000..8fb73ff5cb63 --- /dev/null +++ b/security/tomoyo/memory.c @@ -0,0 +1,236 @@ +/* + * security/tomoyo/memory.c + * + * Memory management functions for TOMOYO. + * + * Copyright (C) 2005-2010  NTT DATA CORPORATION + */ + +#include <linux/hash.h> +#include <linux/slab.h> +#include "common.h" + +/** + * tomoyo_warn_oom - Print out of memory warning message. + * + * @function: Function's name. + */ +void tomoyo_warn_oom(const char *function) +{ +	/* Reduce error messages. */ +	static pid_t tomoyo_last_pid; +	const pid_t pid = current->pid; +	if (tomoyo_last_pid != pid) { +		printk(KERN_WARNING "ERROR: Out of memory at %s.\n", +		       function); +		tomoyo_last_pid = pid; +	} +	if (!tomoyo_policy_loaded) +		panic("MAC Initialization failed.\n"); +} + +/* Memory allocated for policy. */ +static atomic_t tomoyo_policy_memory_size; +/* Quota for holding policy. */ +static unsigned int tomoyo_quota_for_policy; + +/** + * tomoyo_memory_ok - Check memory quota. + * + * @ptr: Pointer to allocated memory. + * + * Returns true on success, false otherwise. + * + * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. + */ +bool tomoyo_memory_ok(void *ptr) +{ +	size_t s = ptr ? ksize(ptr) : 0; +	atomic_add(s, &tomoyo_policy_memory_size); +	if (ptr && (!tomoyo_quota_for_policy || +		    atomic_read(&tomoyo_policy_memory_size) +		    <= tomoyo_quota_for_policy)) { +		memset(ptr, 0, s); +		return true; +	} +	atomic_sub(s, &tomoyo_policy_memory_size); +	tomoyo_warn_oom(__func__); +	return false; +} + +/** + * tomoyo_commit_ok - Check memory quota. + * + * @data:   Data to copy from. + * @size:   Size in byte. + * + * Returns pointer to allocated memory on success, NULL otherwise. + * @data is zero-cleared on success. + */ +void *tomoyo_commit_ok(void *data, const unsigned int size) +{ +	void *ptr = kzalloc(size, GFP_NOFS); +	if (tomoyo_memory_ok(ptr)) { +		memmove(ptr, data, size); +		memset(data, 0, size); +		return ptr; +	} +	return NULL; +} + +/** + * tomoyo_memory_free - Free memory for elements. + * + * @ptr:  Pointer to allocated memory. + */ +void tomoyo_memory_free(void *ptr) +{ +	atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); +	kfree(ptr); +} + +/* + * tomoyo_name_list is used for holding string data used by TOMOYO. + * Since same string data is likely used for multiple times (e.g. + * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of + * "const struct tomoyo_path_info *". + */ +struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; + +/** + * tomoyo_get_name - Allocate permanent memory for string data. + * + * @name: The string to store into the permernent memory. + * + * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. + */ +const struct tomoyo_path_info *tomoyo_get_name(const char *name) +{ +	struct tomoyo_name_entry *ptr; +	unsigned int hash; +	int len; +	int allocated_len; +	struct list_head *head; + +	if (!name) +		return NULL; +	len = strlen(name) + 1; +	hash = full_name_hash((const unsigned char *) name, len - 1); +	head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; +	if (mutex_lock_interruptible(&tomoyo_policy_lock)) +		return NULL; +	list_for_each_entry(ptr, head, list) { +		if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) +			continue; +		atomic_inc(&ptr->users); +		goto out; +	} +	ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); +	allocated_len = ptr ? ksize(ptr) : 0; +	if (!ptr || (tomoyo_quota_for_policy && +		     atomic_read(&tomoyo_policy_memory_size) + allocated_len +		     > tomoyo_quota_for_policy)) { +		kfree(ptr); +		ptr = NULL; +		tomoyo_warn_oom(__func__); +		goto out; +	} +	atomic_add(allocated_len, &tomoyo_policy_memory_size); +	ptr->entry.name = ((char *) ptr) + sizeof(*ptr); +	memmove((char *) ptr->entry.name, name, len); +	atomic_set(&ptr->users, 1); +	tomoyo_fill_path_info(&ptr->entry); +	list_add_tail(&ptr->list, head); + out: +	mutex_unlock(&tomoyo_policy_lock); +	return ptr ? &ptr->entry : NULL; +} + +/** + * tomoyo_mm_init - Initialize mm related code. + */ +void __init tomoyo_mm_init(void) +{ +	int idx; + +	BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); +	for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) +		INIT_LIST_HEAD(&tomoyo_name_list[idx]); +	INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); +	tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); +	list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); +	idx = tomoyo_read_lock(); +	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) +		panic("Can't register tomoyo_kernel_domain"); +	{ +		/* Load built-in policy. */ +		tomoyo_write_domain_initializer_policy("/sbin/hotplug", +						       false, false); +		tomoyo_write_domain_initializer_policy("/sbin/modprobe", +						       false, false); +	} +	tomoyo_read_unlock(idx); +} + + +/* Memory allocated for query lists. */ +unsigned int tomoyo_query_memory_size; +/* Quota for holding query lists. */ +unsigned int tomoyo_quota_for_query; + +/** + * tomoyo_read_memory_counter - Check for memory usage in bytes. + * + * @head: Pointer to "struct tomoyo_io_buffer". + * + * Returns memory usage. + */ +int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) +{ +	if (!head->read_eof) { +		const unsigned int policy +			= atomic_read(&tomoyo_policy_memory_size); +		const unsigned int query = tomoyo_query_memory_size; +		char buffer[64]; + +		memset(buffer, 0, sizeof(buffer)); +		if (tomoyo_quota_for_policy) +			snprintf(buffer, sizeof(buffer) - 1, +				 "   (Quota: %10u)", +				 tomoyo_quota_for_policy); +		else +			buffer[0] = '\0'; +		tomoyo_io_printf(head, "Policy:       %10u%s\n", policy, +				 buffer); +		if (tomoyo_quota_for_query) +			snprintf(buffer, sizeof(buffer) - 1, +				 "   (Quota: %10u)", +				 tomoyo_quota_for_query); +		else +			buffer[0] = '\0'; +		tomoyo_io_printf(head, "Query lists:  %10u%s\n", query, +				 buffer); +		tomoyo_io_printf(head, "Total:        %10u\n", policy + query); +		head->read_eof = true; +	} +	return 0; +} + +/** + * tomoyo_write_memory_quota - Set memory quota. + * + * @head: Pointer to "struct tomoyo_io_buffer". + * + * Returns 0. + */ +int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) +{ +	char *data = head->write_buf; +	unsigned int size; + +	if (sscanf(data, "Policy: %u", &size) == 1) +		tomoyo_quota_for_policy = size; +	else if (sscanf(data, "Query lists: %u", &size) == 1) +		tomoyo_quota_for_query = size; +	return 0; +} diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 3ceb1724c92d..1fd685a94ad1 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -1,19 +1,15 @@  /*   * security/tomoyo/realpath.c   * - * Get the canonicalized absolute pathnames. The basis for TOMOYO. - * - * Copyright (C) 2005-2009  NTT DATA CORPORATION - * - * Version: 2.2.0   2009/04/01 + * Pathname calculation functions for TOMOYO.   * + * Copyright (C) 2005-2010  NTT DATA CORPORATION   */  #include <linux/types.h>  #include <linux/mount.h>  #include <linux/mnt_namespace.h>  #include <linux/fs_struct.h> -#include <linux/hash.h>  #include <linux/magic.h>  #include <linux/slab.h>  #include "common.h" @@ -123,7 +119,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname,  		}  	}  	if (error) -		printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n"); +		tomoyo_warn_oom(__func__);  	return error;  } @@ -141,6 +137,7 @@ char *tomoyo_realpath_from_path(struct path *path)  {  	char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS); +	BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);  	BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer)  		     <= TOMOYO_MAX_PATHNAME_LEN - 1);  	if (!buf) @@ -189,206 +186,3 @@ char *tomoyo_realpath_nofollow(const char *pathname)  	}  	return NULL;  } - -/* Memory allocated for non-string data. */ -static atomic_t tomoyo_policy_memory_size; -/* Quota for holding policy. */ -static unsigned int tomoyo_quota_for_policy; - -/** - * tomoyo_memory_ok - Check memory quota. - * - * @ptr: Pointer to allocated memory. - * - * Returns true on success, false otherwise. - * - * Caller holds tomoyo_policy_lock. - * Memory pointed by @ptr will be zeroed on success. - */ -bool tomoyo_memory_ok(void *ptr) -{ -	int allocated_len = ptr ? ksize(ptr) : 0; -	atomic_add(allocated_len, &tomoyo_policy_memory_size); -	if (ptr && (!tomoyo_quota_for_policy || -		    atomic_read(&tomoyo_policy_memory_size) -		    <= tomoyo_quota_for_policy)) { -		memset(ptr, 0, allocated_len); -		return true; -	} -	printk(KERN_WARNING "ERROR: Out of memory " -	       "for tomoyo_alloc_element().\n"); -	if (!tomoyo_policy_loaded) -		panic("MAC Initialization failed.\n"); -	return false; -} - -/** - * tomoyo_commit_ok - Check memory quota. - * - * @data:   Data to copy from. - * @size:   Size in byte. - * - * Returns pointer to allocated memory on success, NULL otherwise. - */ -void *tomoyo_commit_ok(void *data, const unsigned int size) -{ -	void *ptr = kzalloc(size, GFP_NOFS); -	if (tomoyo_memory_ok(ptr)) { -		memmove(ptr, data, size); -		memset(data, 0, size); -		return ptr; -	} -	return NULL; -} - -/** - * tomoyo_memory_free - Free memory for elements. - * - * @ptr:  Pointer to allocated memory. - */ -void tomoyo_memory_free(void *ptr) -{ -	atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); -	kfree(ptr); -} - -/* - * tomoyo_name_list is used for holding string data used by TOMOYO. - * Since same string data is likely used for multiple times (e.g. - * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of - * "const struct tomoyo_path_info *". - */ -struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; - -/** - * tomoyo_get_name - Allocate permanent memory for string data. - * - * @name: The string to store into the permernent memory. - * - * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. - */ -const struct tomoyo_path_info *tomoyo_get_name(const char *name) -{ -	struct tomoyo_name_entry *ptr; -	unsigned int hash; -	int len; -	int allocated_len; -	struct list_head *head; - -	if (!name) -		return NULL; -	len = strlen(name) + 1; -	hash = full_name_hash((const unsigned char *) name, len - 1); -	head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; -	if (mutex_lock_interruptible(&tomoyo_policy_lock)) -		return NULL; -	list_for_each_entry(ptr, head, list) { -		if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) -			continue; -		atomic_inc(&ptr->users); -		goto out; -	} -	ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); -	allocated_len = ptr ? ksize(ptr) : 0; -	if (!ptr || (tomoyo_quota_for_policy && -		     atomic_read(&tomoyo_policy_memory_size) + allocated_len -		     > tomoyo_quota_for_policy)) { -		kfree(ptr); -		printk(KERN_WARNING "ERROR: Out of memory " -		       "for tomoyo_get_name().\n"); -		if (!tomoyo_policy_loaded) -			panic("MAC Initialization failed.\n"); -		ptr = NULL; -		goto out; -	} -	atomic_add(allocated_len, &tomoyo_policy_memory_size); -	ptr->entry.name = ((char *) ptr) + sizeof(*ptr); -	memmove((char *) ptr->entry.name, name, len); -	atomic_set(&ptr->users, 1); -	tomoyo_fill_path_info(&ptr->entry); -	list_add_tail(&ptr->list, head); - out: -	mutex_unlock(&tomoyo_policy_lock); -	return ptr ? &ptr->entry : NULL; -} - -/** - * tomoyo_realpath_init - Initialize realpath related code. - */ -void __init tomoyo_realpath_init(void) -{ -	int i; - -	BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX); -	for (i = 0; i < TOMOYO_MAX_HASH; i++) -		INIT_LIST_HEAD(&tomoyo_name_list[i]); -	INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); -	tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); -	/* -	 * tomoyo_read_lock() is not needed because this function is -	 * called before the first "delete" request. -	 */ -	list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); -	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) -		panic("Can't register tomoyo_kernel_domain"); -} - -unsigned int tomoyo_quota_for_query; -unsigned int tomoyo_query_memory_size; - -/** - * tomoyo_read_memory_counter - Check for memory usage in bytes. - * - * @head: Pointer to "struct tomoyo_io_buffer". - * - * Returns memory usage. - */ -int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) -{ -	if (!head->read_eof) { -		const unsigned int policy -			= atomic_read(&tomoyo_policy_memory_size); -		const unsigned int query = tomoyo_query_memory_size; -		char buffer[64]; - -		memset(buffer, 0, sizeof(buffer)); -		if (tomoyo_quota_for_policy) -			snprintf(buffer, sizeof(buffer) - 1, -				 "   (Quota: %10u)", -				 tomoyo_quota_for_policy); -		else -			buffer[0] = '\0'; -		tomoyo_io_printf(head, "Policy:       %10u%s\n", policy, -				 buffer); -		if (tomoyo_quota_for_query) -			snprintf(buffer, sizeof(buffer) - 1, -				 "   (Quota: %10u)", -				 tomoyo_quota_for_query); -		else -			buffer[0] = '\0'; -		tomoyo_io_printf(head, "Query lists:  %10u%s\n", query, -				 buffer); -		tomoyo_io_printf(head, "Total:        %10u\n", policy + query); -		head->read_eof = true; -	} -	return 0; -} - -/** - * tomoyo_write_memory_quota - Set memory quota. - * - * @head: Pointer to "struct tomoyo_io_buffer". - * - * Returns 0. - */ -int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) -{ -	char *data = head->write_buf; -	unsigned int size; - -	if (sscanf(data, "Policy: %u", &size) == 1) -		tomoyo_quota_for_policy = size; -	else if (sscanf(data, "Query lists: %u", &size) == 1) -		tomoyo_quota_for_query = size; -	return 0; -} diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c new file mode 100644 index 000000000000..5eb53510c4a7 --- /dev/null +++ b/security/tomoyo/securityfs_if.c @@ -0,0 +1,140 @@ +/* + * security/tomoyo/common.c + * + * Securityfs interface for TOMOYO. + * + * Copyright (C) 2005-2010  NTT DATA CORPORATION + */ + +#include <linux/security.h> +#include "common.h" + +/** + * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. + * + * @inode: Pointer to "struct inode". + * @file:  Pointer to "struct file". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_open(struct inode *inode, struct file *file) +{ +	const int key = ((u8 *) file->f_path.dentry->d_inode->i_private) +		- ((u8 *) NULL); +	return tomoyo_open_control(key, file); +} + +/** + * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. + * + * @inode: Pointer to "struct inode". + * @file:  Pointer to "struct file". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_release(struct inode *inode, struct file *file) +{ +	return tomoyo_close_control(file); +} + +/** + * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. + * + * @file:  Pointer to "struct file". + * @buf:   Pointer to buffer. + * @count: Size of @buf. + * @ppos:  Unused. + * + * Returns bytes read on success, negative value otherwise. + */ +static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, +			   loff_t *ppos) +{ +	return tomoyo_read_control(file, buf, count); +} + +/** + * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. + * + * @file:  Pointer to "struct file". + * @buf:   Pointer to buffer. + * @count: Size of @buf. + * @ppos:  Unused. + * + * Returns @count on success, negative value otherwise. + */ +static ssize_t tomoyo_write(struct file *file, const char __user *buf, +			    size_t count, loff_t *ppos) +{ +	return tomoyo_write_control(file, buf, count); +} + +/* + * tomoyo_operations is a "struct file_operations" which is used for handling + * /sys/kernel/security/tomoyo/ interface. + * + * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). + * See tomoyo_io_buffer for internals. + */ +static const struct file_operations tomoyo_operations = { +	.open    = tomoyo_open, +	.release = tomoyo_release, +	.read    = tomoyo_read, +	.write   = tomoyo_write, +}; + +/** + * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. + * + * @name:   The name of the interface file. + * @mode:   The permission of the interface file. + * @parent: The parent directory. + * @key:    Type of interface. + * + * Returns nothing. + */ +static void __init tomoyo_create_entry(const char *name, const mode_t mode, +				       struct dentry *parent, const u8 key) +{ +	securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key, +			       &tomoyo_operations); +} + +/** + * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. + * + * Returns 0. + */ +static int __init tomoyo_initerface_init(void) +{ +	struct dentry *tomoyo_dir; + +	/* Don't create securityfs entries unless registered. */ +	if (current_cred()->security != &tomoyo_kernel_domain) +		return 0; + +	tomoyo_dir = securityfs_create_dir("tomoyo", NULL); +	tomoyo_create_entry("query",            0600, tomoyo_dir, +			    TOMOYO_QUERY); +	tomoyo_create_entry("domain_policy",    0600, tomoyo_dir, +			    TOMOYO_DOMAINPOLICY); +	tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, +			    TOMOYO_EXCEPTIONPOLICY); +	tomoyo_create_entry("self_domain",      0400, tomoyo_dir, +			    TOMOYO_SELFDOMAIN); +	tomoyo_create_entry(".domain_status",   0600, tomoyo_dir, +			    TOMOYO_DOMAIN_STATUS); +	tomoyo_create_entry(".process_status",  0600, tomoyo_dir, +			    TOMOYO_PROCESS_STATUS); +	tomoyo_create_entry("meminfo",          0600, tomoyo_dir, +			    TOMOYO_MEMINFO); +	tomoyo_create_entry("profile",          0600, tomoyo_dir, +			    TOMOYO_PROFILE); +	tomoyo_create_entry("manager",          0600, tomoyo_dir, +			    TOMOYO_MANAGER); +	tomoyo_create_entry("version",          0400, tomoyo_dir, +			    TOMOYO_VERSION); +	return 0; +} + +fs_initcall(tomoyo_initerface_init); diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 5d64d409b112..57d442e7339b 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -3,10 +3,7 @@   *   * LSM hooks for TOMOYO Linux.   * - * Copyright (C) 2005-2009  NTT DATA CORPORATION - * - * Version: 2.2.0   2009/04/01 - * + * Copyright (C) 2005-2010  NTT DATA CORPORATION   */  #include <linux/security.h> @@ -286,7 +283,7 @@ static int __init tomoyo_init(void)  		panic("Failure registering TOMOYO Linux");  	printk(KERN_INFO "TOMOYO Linux initialized\n");  	cred->security = &tomoyo_kernel_domain; -	tomoyo_realpath_init(); +	tomoyo_mm_init();  	return 0;  } diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c new file mode 100644 index 000000000000..7b023f5e1314 --- /dev/null +++ b/security/tomoyo/util.c @@ -0,0 +1,951 @@ +/* + * security/tomoyo/util.c + * + * Utility functions for TOMOYO. + * + * Copyright (C) 2005-2010  NTT DATA CORPORATION + */ + +#include <linux/slab.h> +#include "common.h" + +/* Lock for protecting policy. */ +DEFINE_MUTEX(tomoyo_policy_lock); + +/* Has /sbin/init started? */ +bool tomoyo_policy_loaded; + +/** + * tomoyo_parse_ulong - Parse an "unsigned long" value. + * + * @result: Pointer to "unsigned long". + * @str:    Pointer to string to parse. + * + * Returns value type on success, 0 otherwise. + * + * The @src is updated to point the first character after the value + * on success. + */ +u8 tomoyo_parse_ulong(unsigned long *result, char **str) +{ +	const char *cp = *str; +	char *ep; +	int base = 10; +	if (*cp == '0') { +		char c = *(cp + 1); +		if (c == 'x' || c == 'X') { +			base = 16; +			cp += 2; +		} else if (c >= '0' && c <= '7') { +			base = 8; +			cp++; +		} +	} +	*result = simple_strtoul(cp, &ep, base); +	if (cp == ep) +		return 0; +	*str = ep; +	switch (base) { +	case 16: +		return TOMOYO_VALUE_TYPE_HEXADECIMAL; +	case 8: +		return TOMOYO_VALUE_TYPE_OCTAL; +	default: +		return TOMOYO_VALUE_TYPE_DECIMAL; +	} +} + +/** + * tomoyo_print_ulong - Print an "unsigned long" value. + * + * @buffer:     Pointer to buffer. + * @buffer_len: Size of @buffer. + * @value:      An "unsigned long" value. + * @type:       Type of @value. + * + * Returns nothing. + */ +void tomoyo_print_ulong(char *buffer, const int buffer_len, +			const unsigned long value, const u8 type) +{ +	if (type == TOMOYO_VALUE_TYPE_DECIMAL) +		snprintf(buffer, buffer_len, "%lu", value); +	else if (type == TOMOYO_VALUE_TYPE_OCTAL) +		snprintf(buffer, buffer_len, "0%lo", value); +	else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL) +		snprintf(buffer, buffer_len, "0x%lX", value); +	else +		snprintf(buffer, buffer_len, "type(%u)", type); +} + +/** + * tomoyo_parse_name_union - Parse a tomoyo_name_union. + * + * @filename: Name or name group. + * @ptr:      Pointer to "struct tomoyo_name_union". + * + * Returns true on success, false otherwise. + */ +bool tomoyo_parse_name_union(const char *filename, +			     struct tomoyo_name_union *ptr) +{ +	if (!tomoyo_is_correct_path(filename, 0, 0, 0)) +		return false; +	if (filename[0] == '@') { +		ptr->group = tomoyo_get_path_group(filename + 1); +		ptr->is_group = true; +		return ptr->group != NULL; +	} +	ptr->filename = tomoyo_get_name(filename); +	ptr->is_group = false; +	return ptr->filename != NULL; +} + +/** + * tomoyo_parse_number_union - Parse a tomoyo_number_union. + * + * @data: Number or number range or number group. + * @ptr:  Pointer to "struct tomoyo_number_union". + * + * Returns true on success, false otherwise. + */ +bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num) +{ +	u8 type; +	unsigned long v; +	memset(num, 0, sizeof(*num)); +	if (data[0] == '@') { +		if (!tomoyo_is_correct_path(data, 0, 0, 0)) +			return false; +		num->group = tomoyo_get_number_group(data + 1); +		num->is_group = true; +		return num->group != NULL; +	} +	type = tomoyo_parse_ulong(&v, &data); +	if (!type) +		return false; +	num->values[0] = v; +	num->min_type = type; +	if (!*data) { +		num->values[1] = v; +		num->max_type = type; +		return true; +	} +	if (*data++ != '-') +		return false; +	type = tomoyo_parse_ulong(&v, &data); +	if (!type || *data) +		return false; +	num->values[1] = v; +	num->max_type = type; +	return true; +} + +/** + * tomoyo_is_byte_range - Check whether the string is a \ooo style octal value. + * + * @str: Pointer to the string. + * + * Returns true if @str is a \ooo style octal value, false otherwise. + * + * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. + * This function verifies that \ooo is in valid range. + */ +static inline bool tomoyo_is_byte_range(const char *str) +{ +	return *str >= '0' && *str++ <= '3' && +		*str >= '0' && *str++ <= '7' && +		*str >= '0' && *str <= '7'; +} + +/** + * tomoyo_is_alphabet_char - Check whether the character is an alphabet. + * + * @c: The character to check. + * + * Returns true if @c is an alphabet character, false otherwise. + */ +static inline bool tomoyo_is_alphabet_char(const char c) +{ +	return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +/** + * tomoyo_make_byte - Make byte value from three octal characters. + * + * @c1: The first character. + * @c2: The second character. + * @c3: The third character. + * + * Returns byte value. + */ +static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) +{ +	return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); +} + +/** + * tomoyo_str_starts - Check whether the given string starts with the given keyword. + * + * @src:  Pointer to pointer to the string. + * @find: Pointer to the keyword. + * + * Returns true if @src starts with @find, false otherwise. + * + * The @src is updated to point the first character after the @find + * if @src starts with @find. + */ +bool tomoyo_str_starts(char **src, const char *find) +{ +	const int len = strlen(find); +	char *tmp = *src; + +	if (strncmp(tmp, find, len)) +		return false; +	tmp += len; +	*src = tmp; +	return true; +} + +/** + * tomoyo_normalize_line - Format string. + * + * @buffer: The line to normalize. + * + * Leading and trailing whitespaces are removed. + * Multiple whitespaces are packed into single space. + * + * Returns nothing. + */ +void tomoyo_normalize_line(unsigned char *buffer) +{ +	unsigned char *sp = buffer; +	unsigned char *dp = buffer; +	bool first = true; + +	while (tomoyo_is_invalid(*sp)) +		sp++; +	while (*sp) { +		if (!first) +			*dp++ = ' '; +		first = false; +		while (tomoyo_is_valid(*sp)) +			*dp++ = *sp++; +		while (tomoyo_is_invalid(*sp)) +			sp++; +	} +	*dp = '\0'; +} + +/** + * tomoyo_tokenize - Tokenize string. + * + * @buffer: The line to tokenize. + * @w:      Pointer to "char *". + * @size:   Sizeof @w . + * + * Returns true on success, false otherwise. + */ +bool tomoyo_tokenize(char *buffer, char *w[], size_t size) +{ +	int count = size / sizeof(char *); +	int i; +	for (i = 0; i < count; i++) +		w[i] = ""; +	for (i = 0; i < count; i++) { +		char *cp = strchr(buffer, ' '); +		if (cp) +			*cp = '\0'; +		w[i] = buffer; +		if (!cp) +			break; +		buffer = cp + 1; +	} +	return i < count || !*buffer; +} + +/** + * tomoyo_is_correct_path - Validate a pathname. + * + * @filename:     The pathname to check. + * @start_type:   Should the pathname start with '/'? + *                1 = must / -1 = must not / 0 = don't care + * @pattern_type: Can the pathname contain a wildcard? + *                1 = must / -1 = must not / 0 = don't care + * @end_type:     Should the pathname end with '/'? + *                1 = must / -1 = must not / 0 = don't care + * + * Check whether the given filename follows the naming rules. + * Returns true if @filename follows the naming rules, false otherwise. + */ +bool tomoyo_is_correct_path(const char *filename, const s8 start_type, +			    const s8 pattern_type, const s8 end_type) +{ +	const char *const start = filename; +	bool in_repetition = false; +	bool contains_pattern = false; +	unsigned char c; +	unsigned char d; +	unsigned char e; + +	if (!filename) +		goto out; +	c = *filename; +	if (start_type == 1) { /* Must start with '/' */ +		if (c != '/') +			goto out; +	} else if (start_type == -1) { /* Must not start with '/' */ +		if (c == '/') +			goto out; +	} +	if (c) +		c = *(filename + strlen(filename) - 1); +	if (end_type == 1) { /* Must end with '/' */ +		if (c != '/') +			goto out; +	} else if (end_type == -1) { /* Must not end with '/' */ +		if (c == '/') +			goto out; +	} +	while (1) { +		c = *filename++; +		if (!c) +			break; +		if (c == '\\') { +			c = *filename++; +			switch (c) { +			case '\\':  /* "\\" */ +				continue; +			case '$':   /* "\$" */ +			case '+':   /* "\+" */ +			case '?':   /* "\?" */ +			case '*':   /* "\*" */ +			case '@':   /* "\@" */ +			case 'x':   /* "\x" */ +			case 'X':   /* "\X" */ +			case 'a':   /* "\a" */ +			case 'A':   /* "\A" */ +			case '-':   /* "\-" */ +				if (pattern_type == -1) +					break; /* Must not contain pattern */ +				contains_pattern = true; +				continue; +			case '{':   /* "/\{" */ +				if (filename - 3 < start || +				    *(filename - 3) != '/') +					break; +				if (pattern_type == -1) +					break; /* Must not contain pattern */ +				contains_pattern = true; +				in_repetition = true; +				continue; +			case '}':   /* "\}/" */ +				if (*filename != '/') +					break; +				if (!in_repetition) +					break; +				in_repetition = false; +				continue; +			case '0':   /* "\ooo" */ +			case '1': +			case '2': +			case '3': +				d = *filename++; +				if (d < '0' || d > '7') +					break; +				e = *filename++; +				if (e < '0' || e > '7') +					break; +				c = tomoyo_make_byte(c, d, e); +				if (tomoyo_is_invalid(c)) +					continue; /* pattern is not \000 */ +			} +			goto out; +		} else if (in_repetition && c == '/') { +			goto out; +		} else if (tomoyo_is_invalid(c)) { +			goto out; +		} +	} +	if (pattern_type == 1) { /* Must contain pattern */ +		if (!contains_pattern) +			goto out; +	} +	if (in_repetition) +		goto out; +	return true; + out: +	return false; +} + +/** + * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. + * + * @domainname:   The domainname to check. + * + * Returns true if @domainname follows the naming rules, false otherwise. + */ +bool tomoyo_is_correct_domain(const unsigned char *domainname) +{ +	unsigned char c; +	unsigned char d; +	unsigned char e; + +	if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, +				   TOMOYO_ROOT_NAME_LEN)) +		goto out; +	domainname += TOMOYO_ROOT_NAME_LEN; +	if (!*domainname) +		return true; +	do { +		if (*domainname++ != ' ') +			goto out; +		if (*domainname++ != '/') +			goto out; +		while ((c = *domainname) != '\0' && c != ' ') { +			domainname++; +			if (c == '\\') { +				c = *domainname++; +				switch ((c)) { +				case '\\':  /* "\\" */ +					continue; +				case '0':   /* "\ooo" */ +				case '1': +				case '2': +				case '3': +					d = *domainname++; +					if (d < '0' || d > '7') +						break; +					e = *domainname++; +					if (e < '0' || e > '7') +						break; +					c = tomoyo_make_byte(c, d, e); +					if (tomoyo_is_invalid(c)) +						/* pattern is not \000 */ +						continue; +				} +				goto out; +			} else if (tomoyo_is_invalid(c)) { +				goto out; +			} +		} +	} while (*domainname); +	return true; + out: +	return false; +} + +/** + * tomoyo_is_domain_def - Check whether the given token can be a domainname. + * + * @buffer: The token to check. + * + * Returns true if @buffer possibly be a domainname, false otherwise. + */ +bool tomoyo_is_domain_def(const unsigned char *buffer) +{ +	return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN); +} + +/** + * tomoyo_find_domain - Find a domain by the given name. + * + * @domainname: The domainname to find. + * + * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) +{ +	struct tomoyo_domain_info *domain; +	struct tomoyo_path_info name; + +	name.name = domainname; +	tomoyo_fill_path_info(&name); +	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { +		if (!domain->is_deleted && +		    !tomoyo_pathcmp(&name, domain->domainname)) +			return domain; +	} +	return NULL; +} + +/** + * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. + * + * @filename: The string to evaluate. + * + * Returns the initial length without a pattern in @filename. + */ +static int tomoyo_const_part_length(const char *filename) +{ +	char c; +	int len = 0; + +	if (!filename) +		return 0; +	while ((c = *filename++) != '\0') { +		if (c != '\\') { +			len++; +			continue; +		} +		c = *filename++; +		switch (c) { +		case '\\':  /* "\\" */ +			len += 2; +			continue; +		case '0':   /* "\ooo" */ +		case '1': +		case '2': +		case '3': +			c = *filename++; +			if (c < '0' || c > '7') +				break; +			c = *filename++; +			if (c < '0' || c > '7') +				break; +			len += 4; +			continue; +		} +		break; +	} +	return len; +} + +/** + * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. + * + * @ptr: Pointer to "struct tomoyo_path_info" to fill in. + * + * The caller sets "struct tomoyo_path_info"->name. + */ +void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) +{ +	const char *name = ptr->name; +	const int len = strlen(name); + +	ptr->const_len = tomoyo_const_part_length(name); +	ptr->is_dir = len && (name[len - 1] == '/'); +	ptr->is_patterned = (ptr->const_len < len); +	ptr->hash = full_name_hash(name, len); +} + +/** + * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern. + * + * @filename:     The start of string to check. + * @filename_end: The end of string to check. + * @pattern:      The start of pattern to compare. + * @pattern_end:  The end of pattern to compare. + * + * Returns true if @filename matches @pattern, false otherwise. + */ +static bool tomoyo_file_matches_pattern2(const char *filename, +					 const char *filename_end, +					 const char *pattern, +					 const char *pattern_end) +{ +	while (filename < filename_end && pattern < pattern_end) { +		char c; +		if (*pattern != '\\') { +			if (*filename++ != *pattern++) +				return false; +			continue; +		} +		c = *filename; +		pattern++; +		switch (*pattern) { +			int i; +			int j; +		case '?': +			if (c == '/') { +				return false; +			} else if (c == '\\') { +				if (filename[1] == '\\') +					filename++; +				else if (tomoyo_is_byte_range(filename + 1)) +					filename += 3; +				else +					return false; +			} +			break; +		case '\\': +			if (c != '\\') +				return false; +			if (*++filename != '\\') +				return false; +			break; +		case '+': +			if (!isdigit(c)) +				return false; +			break; +		case 'x': +			if (!isxdigit(c)) +				return false; +			break; +		case 'a': +			if (!tomoyo_is_alphabet_char(c)) +				return false; +			break; +		case '0': +		case '1': +		case '2': +		case '3': +			if (c == '\\' && tomoyo_is_byte_range(filename + 1) +			    && strncmp(filename + 1, pattern, 3) == 0) { +				filename += 3; +				pattern += 2; +				break; +			} +			return false; /* Not matched. */ +		case '*': +		case '@': +			for (i = 0; i <= filename_end - filename; i++) { +				if (tomoyo_file_matches_pattern2( +						    filename + i, filename_end, +						    pattern + 1, pattern_end)) +					return true; +				c = filename[i]; +				if (c == '.' && *pattern == '@') +					break; +				if (c != '\\') +					continue; +				if (filename[i + 1] == '\\') +					i++; +				else if (tomoyo_is_byte_range(filename + i + 1)) +					i += 3; +				else +					break; /* Bad pattern. */ +			} +			return false; /* Not matched. */ +		default: +			j = 0; +			c = *pattern; +			if (c == '$') { +				while (isdigit(filename[j])) +					j++; +			} else if (c == 'X') { +				while (isxdigit(filename[j])) +					j++; +			} else if (c == 'A') { +				while (tomoyo_is_alphabet_char(filename[j])) +					j++; +			} +			for (i = 1; i <= j; i++) { +				if (tomoyo_file_matches_pattern2( +						    filename + i, filename_end, +						    pattern + 1, pattern_end)) +					return true; +			} +			return false; /* Not matched or bad pattern. */ +		} +		filename++; +		pattern++; +	} +	while (*pattern == '\\' && +	       (*(pattern + 1) == '*' || *(pattern + 1) == '@')) +		pattern += 2; +	return filename == filename_end && pattern == pattern_end; +} + +/** + * tomoyo_file_matches_pattern - Pattern matching without '/' character. + * + * @filename:     The start of string to check. + * @filename_end: The end of string to check. + * @pattern:      The start of pattern to compare. + * @pattern_end:  The end of pattern to compare. + * + * Returns true if @filename matches @pattern, false otherwise. + */ +static bool tomoyo_file_matches_pattern(const char *filename, +					const char *filename_end, +					const char *pattern, +					const char *pattern_end) +{ +	const char *pattern_start = pattern; +	bool first = true; +	bool result; + +	while (pattern < pattern_end - 1) { +		/* Split at "\-" pattern. */ +		if (*pattern++ != '\\' || *pattern++ != '-') +			continue; +		result = tomoyo_file_matches_pattern2(filename, +						      filename_end, +						      pattern_start, +						      pattern - 2); +		if (first) +			result = !result; +		if (result) +			return false; +		first = false; +		pattern_start = pattern; +	} +	result = tomoyo_file_matches_pattern2(filename, filename_end, +					      pattern_start, pattern_end); +	return first ? result : !result; +} + +/** + * tomoyo_path_matches_pattern2 - Do pathname pattern matching. + * + * @f: The start of string to check. + * @p: The start of pattern to compare. + * + * Returns true if @f matches @p, false otherwise. + */ +static bool tomoyo_path_matches_pattern2(const char *f, const char *p) +{ +	const char *f_delimiter; +	const char *p_delimiter; + +	while (*f && *p) { +		f_delimiter = strchr(f, '/'); +		if (!f_delimiter) +			f_delimiter = f + strlen(f); +		p_delimiter = strchr(p, '/'); +		if (!p_delimiter) +			p_delimiter = p + strlen(p); +		if (*p == '\\' && *(p + 1) == '{') +			goto recursive; +		if (!tomoyo_file_matches_pattern(f, f_delimiter, p, +						 p_delimiter)) +			return false; +		f = f_delimiter; +		if (*f) +			f++; +		p = p_delimiter; +		if (*p) +			p++; +	} +	/* Ignore trailing "\*" and "\@" in @pattern. */ +	while (*p == '\\' && +	       (*(p + 1) == '*' || *(p + 1) == '@')) +		p += 2; +	return !*f && !*p; + recursive: +	/* +	 * The "\{" pattern is permitted only after '/' character. +	 * This guarantees that below "*(p - 1)" is safe. +	 * Also, the "\}" pattern is permitted only before '/' character +	 * so that "\{" + "\}" pair will not break the "\-" operator. +	 */ +	if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || +	    *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') +		return false; /* Bad pattern. */ +	do { +		/* Compare current component with pattern. */ +		if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, +						 p_delimiter - 2)) +			break; +		/* Proceed to next component. */ +		f = f_delimiter; +		if (!*f) +			break; +		f++; +		/* Continue comparison. */ +		if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) +			return true; +		f_delimiter = strchr(f, '/'); +	} while (f_delimiter); +	return false; /* Not matched. */ +} + +/** + * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. + * + * @filename: The filename to check. + * @pattern:  The pattern to compare. + * + * Returns true if matches, false otherwise. + * + * The following patterns are available. + *   \\     \ itself. + *   \ooo   Octal representation of a byte. + *   \*     Zero or more repetitions of characters other than '/'. + *   \@     Zero or more repetitions of characters other than '/' or '.'. + *   \?     1 byte character other than '/'. + *   \$     One or more repetitions of decimal digits. + *   \+     1 decimal digit. + *   \X     One or more repetitions of hexadecimal digits. + *   \x     1 hexadecimal digit. + *   \A     One or more repetitions of alphabet characters. + *   \a     1 alphabet character. + * + *   \-     Subtraction operator. + * + *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ + *               /dir/dir/dir/ ). + */ +bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, +				 const struct tomoyo_path_info *pattern) +{ +	const char *f = filename->name; +	const char *p = pattern->name; +	const int len = pattern->const_len; + +	/* If @pattern doesn't contain pattern, I can use strcmp(). */ +	if (!pattern->is_patterned) +		return !tomoyo_pathcmp(filename, pattern); +	/* Don't compare directory and non-directory. */ +	if (filename->is_dir != pattern->is_dir) +		return false; +	/* Compare the initial length without patterns. */ +	if (strncmp(f, p, len)) +		return false; +	f += len; +	p += len; +	return tomoyo_path_matches_pattern2(f, p); +} + +/** + * tomoyo_get_exe - Get tomoyo_realpath() of current process. + * + * Returns the tomoyo_realpath() of current process on success, NULL otherwise. + * + * This function uses kzalloc(), so the caller must call kfree() + * if this function didn't return NULL. + */ +const char *tomoyo_get_exe(void) +{ +	struct mm_struct *mm = current->mm; +	struct vm_area_struct *vma; +	const char *cp = NULL; + +	if (!mm) +		return NULL; +	down_read(&mm->mmap_sem); +	for (vma = mm->mmap; vma; vma = vma->vm_next) { +		if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { +			cp = tomoyo_realpath_from_path(&vma->vm_file->f_path); +			break; +		} +	} +	up_read(&mm->mmap_sem); +	return cp; +} + +/** + * 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(). + * + * Returns mode. + */ +int tomoyo_init_request_info(struct tomoyo_request_info *r, +			     struct tomoyo_domain_info *domain) +{ +	memset(r, 0, sizeof(*r)); +	if (!domain) +		domain = tomoyo_domain(); +	r->domain = domain; +	r->mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); +	return r->mode; +} + +/** + * tomoyo_warn_log - Print warning or error message on console. + * + * @r:   Pointer to "struct tomoyo_request_info". + * @fmt: The printf()'s format string, followed by parameters. + */ +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) +			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); +	} +	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)); +	kfree(buffer); +} + +/** + * tomoyo_domain_quota_is_ok - Check for domain's quota. + * + * @r: Pointer to "struct tomoyo_request_info". + * + * Returns true if the domain is not exceeded quota, false otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) +{ +	unsigned int count = 0; +	struct tomoyo_domain_info *domain = r->domain; +	struct tomoyo_acl_info *ptr; + +	if (r->mode != TOMOYO_CONFIG_LEARNING) +		return false; +	if (!domain) +		return true; +	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { +		switch (ptr->type) { +			u16 perm; +			u8 i; +		case TOMOYO_TYPE_PATH_ACL: +			perm = container_of(ptr, struct tomoyo_path_acl, head) +				->perm; +			for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++) +				if (perm & (1 << i)) +					count++; +			if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) +				count -= 2; +			break; +		case TOMOYO_TYPE_PATH2_ACL: +			perm = container_of(ptr, struct tomoyo_path2_acl, head) +				->perm; +			for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++) +				if (perm & (1 << i)) +					count++; +			break; +		case TOMOYO_TYPE_PATH_NUMBER_ACL: +			perm = container_of(ptr, struct tomoyo_path_number_acl, +					    head)->perm; +			for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++) +				if (perm & (1 << i)) +					count++; +			break; +		case TOMOYO_TYPE_PATH_NUMBER3_ACL: +			perm = container_of(ptr, struct tomoyo_path_number3_acl, +					    head)->perm; +			for (i = 0; i < TOMOYO_MAX_PATH_NUMBER3_OPERATION; i++) +				if (perm & (1 << i)) +					count++; +			break; +		case TOMOYO_TYPE_MOUNT_ACL: +			if (!container_of(ptr, struct tomoyo_mount_acl, head)-> +			    is_deleted) +				count++; +		} +	} +	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) +		return true; +	if (!domain->quota_warned) { +		domain->quota_warned = true; +		printk(KERN_WARNING "TOMOYO-WARNING: " +		       "Domain '%s' has so many ACLs to hold. " +		       "Stopped learning mode.\n", domain->domainname->name); +	} +	return false; +} |