diff options
Diffstat (limited to 'security/tomoyo/file.c')
| -rw-r--r-- | security/tomoyo/file.c | 1533 | 
1 files changed, 712 insertions, 821 deletions
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 1c6f8238ec4..9d32f182301 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -1,48 +1,88 @@  /*   * 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"  #include <linux/slab.h> -/* Keyword array for single path operations. */ -static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { +/* Keyword array for operations with one pathname. */ +const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {  	[TOMOYO_TYPE_READ_WRITE] = "read/write",  	[TOMOYO_TYPE_EXECUTE]    = "execute",  	[TOMOYO_TYPE_READ]       = "read",  	[TOMOYO_TYPE_WRITE]      = "write", -	[TOMOYO_TYPE_CREATE]     = "create",  	[TOMOYO_TYPE_UNLINK]     = "unlink", -	[TOMOYO_TYPE_MKDIR]      = "mkdir",  	[TOMOYO_TYPE_RMDIR]      = "rmdir", -	[TOMOYO_TYPE_MKFIFO]     = "mkfifo", -	[TOMOYO_TYPE_MKSOCK]     = "mksock", -	[TOMOYO_TYPE_MKBLOCK]    = "mkblock", -	[TOMOYO_TYPE_MKCHAR]     = "mkchar",  	[TOMOYO_TYPE_TRUNCATE]   = "truncate",  	[TOMOYO_TYPE_SYMLINK]    = "symlink",  	[TOMOYO_TYPE_REWRITE]    = "rewrite", +	[TOMOYO_TYPE_CHROOT]     = "chroot", +	[TOMOYO_TYPE_UMOUNT]     = "unmount", +}; + +/* Keyword array for operations with one pathname and three numbers. */ +const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = { +	[TOMOYO_TYPE_MKBLOCK]    = "mkblock", +	[TOMOYO_TYPE_MKCHAR]     = "mkchar", +}; + +/* Keyword array for operations with two pathnames. */ +const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { +	[TOMOYO_TYPE_LINK]       = "link", +	[TOMOYO_TYPE_RENAME]     = "rename", +	[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", +}; + +/* Keyword array for operations with one pathname and one number. */ +const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { +	[TOMOYO_TYPE_CREATE]     = "create", +	[TOMOYO_TYPE_MKDIR]      = "mkdir", +	[TOMOYO_TYPE_MKFIFO]     = "mkfifo", +	[TOMOYO_TYPE_MKSOCK]     = "mksock",  	[TOMOYO_TYPE_IOCTL]      = "ioctl",  	[TOMOYO_TYPE_CHMOD]      = "chmod",  	[TOMOYO_TYPE_CHOWN]      = "chown",  	[TOMOYO_TYPE_CHGRP]      = "chgrp", -	[TOMOYO_TYPE_CHROOT]     = "chroot", -	[TOMOYO_TYPE_MOUNT]      = "mount", -	[TOMOYO_TYPE_UMOUNT]     = "unmount",  }; -/* Keyword array for double path operations. */ -static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { -	[TOMOYO_TYPE_LINK]    = "link", -	[TOMOYO_TYPE_RENAME]  = "rename", -	[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", +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_MKDEV_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) @@ -50,56 +90,45 @@ void tomoyo_put_name_union(struct tomoyo_name_union *ptr)  	if (!ptr)  		return;  	if (ptr->is_group) -		tomoyo_put_path_group(ptr->group); +		tomoyo_put_group(ptr->group);  	else  		tomoyo_put_name(ptr->filename);  } -bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, -			       const struct tomoyo_name_union *ptr) +const struct tomoyo_path_info * +tomoyo_compare_name_union(const struct tomoyo_path_info *name, +			  const struct tomoyo_name_union *ptr)  {  	if (ptr->is_group) -		return tomoyo_path_matches_group(name, ptr->group, 1); -	return tomoyo_path_matches_pattern(name, ptr->filename); +		return tomoyo_path_matches_group(name, ptr->group); +	if (tomoyo_path_matches_pattern(name, ptr->filename)) +		return ptr->filename; +	return NULL;  } -static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info -					      *name, -					      const struct tomoyo_name_union -					      *ptr, const bool may_use_pattern) +void tomoyo_put_number_union(struct tomoyo_number_union *ptr)  { -	if (ptr->is_group) -		return tomoyo_path_matches_group(name, ptr->group, -						 may_use_pattern); -	if (may_use_pattern || !ptr->filename->is_patterned) -		return tomoyo_path_matches_pattern(name, ptr->filename); -	return false; +	if (ptr && ptr->is_group) +		tomoyo_put_group(ptr->group);  } -/** - * tomoyo_path2keyword - Get the name of single path operation. - * - * @operation: Type of operation. - * - * Returns the name of single path operation. - */ -const char *tomoyo_path2keyword(const u8 operation) +bool tomoyo_compare_number_union(const unsigned long value, +				 const struct tomoyo_number_union *ptr)  { -	return (operation < TOMOYO_MAX_PATH_OPERATION) -		? tomoyo_path_keyword[operation] : NULL; +	if (ptr->is_group) +		return tomoyo_number_matches_group(value, value, ptr->group); +	return value >= ptr->values[0] && value <= ptr->values[1];  } -/** - * tomoyo_path22keyword - Get the name of double path operation. - * - * @operation: Type of operation. - * - * Returns the name of double path operation. - */ -const char *tomoyo_path22keyword(const u8 operation) +static void tomoyo_add_slash(struct tomoyo_path_info *buf)  { -	return (operation < TOMOYO_MAX_PATH2_OPERATION) -		? tomoyo_path2_keyword[operation] : NULL; +	if (buf->is_dir) +		return; +	/* +	 * This is OK because tomoyo_encode() reserves space for appending "/". +	 */ +	strcat((char *) buf->name, "/"); +	tomoyo_fill_path_info(buf);  }  /** @@ -121,69 +150,134 @@ static bool tomoyo_strendswith(const char *name, const char *tail)  }  /** - * tomoyo_get_path - Get realpath. + * tomoyo_get_realpath - Get realpath.   * + * @buf:  Pointer to "struct tomoyo_path_info".   * @path: Pointer to "struct path".   * - * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. + * Returns true on success, false otherwise.   */ -static struct tomoyo_path_info *tomoyo_get_path(struct path *path) +static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)  { -	int error; -	struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), -							 GFP_NOFS); - -	if (!buf) -		return NULL; -	/* Reserve one byte for appending "/". */ -	error = tomoyo_realpath_from_path2(path, buf->body, -					   sizeof(buf->body) - 2); -	if (!error) { -		buf->head.name = buf->body; -		tomoyo_fill_path_info(&buf->head); -		return &buf->head; +	buf->name = tomoyo_realpath_from_path(path); +	if (buf->name) { +		tomoyo_fill_path_info(buf); +		return true;  	} -	kfree(buf); -	return NULL; +        return false;  } -static int tomoyo_update_path2_acl(const u8 type, const char *filename1, -				   const char *filename2, -				   struct tomoyo_domain_info *const domain, -				   const bool is_delete); -static int tomoyo_update_path_acl(const u8 type, const char *filename, -				  struct tomoyo_domain_info *const domain, -				  const bool is_delete); - -/* - * tomoyo_globally_readable_list is used for holding list of pathnames which - * are by default allowed to be open()ed for reading by any process. +/** + * tomoyo_audit_path_log - Audit path request log. + * + * @r: Pointer to "struct tomoyo_request_info".   * - * An entry is added by + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_audit_path_log(struct tomoyo_request_info *r) +{ +	const char *operation = tomoyo_path_keyword[r->param.path.operation]; +	const struct tomoyo_path_info *filename = r->param.path.filename; +	if (r->granted) +		return 0; +	tomoyo_warn_log(r, "%s %s", operation, filename->name); +	return tomoyo_supervisor(r, "allow_%s %s\n", operation, +				 tomoyo_pattern(filename)); +} + +/** + * tomoyo_audit_path2_log - Audit path/path request log.   * - * # echo 'allow_read /lib/libc-2.5.so' > \ - *                               /sys/kernel/security/tomoyo/exception_policy + * @r: Pointer to "struct tomoyo_request_info".   * - * and is deleted by + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) +{ +	const char *operation = tomoyo_path2_keyword[r->param.path2.operation]; +	const struct tomoyo_path_info *filename1 = r->param.path2.filename1; +	const struct tomoyo_path_info *filename2 = r->param.path2.filename2; +	if (r->granted) +		return 0; +	tomoyo_warn_log(r, "%s %s %s", operation, filename1->name, +			filename2->name); +	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, +				 tomoyo_pattern(filename1), +				 tomoyo_pattern(filename2)); +} + +/** + * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.   * - * # echo 'delete allow_read /lib/libc-2.5.so' > \ - *                               /sys/kernel/security/tomoyo/exception_policy + * @r: Pointer to "struct tomoyo_request_info".   * - * and all entries are retrieved by + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) +{ +	const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation]; +	const struct tomoyo_path_info *filename = r->param.mkdev.filename; +	const unsigned int major = r->param.mkdev.major; +	const unsigned int minor = r->param.mkdev.minor; +	const unsigned int mode = r->param.mkdev.mode; +	if (r->granted) +		return 0; +	tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode, +			major, minor); +	return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation, +				 tomoyo_pattern(filename), mode, major, minor); +} + +/** + * tomoyo_audit_path_number_log - Audit path/number request log.   * - * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy + * @r:     Pointer to "struct tomoyo_request_info". + * @error: Error code.   * - * In the example above, any process is allowed to - * open("/lib/libc-2.5.so", O_RDONLY). - * One exception is, if the domain which current process belongs to is marked - * as "ignore_global_allow_read", current process can't do so unless explicitly - * given "allow_read /lib/libc-2.5.so" to the domain which current process - * belongs to. + * Returns 0 on success, negative value otherwise.   */ -LIST_HEAD(tomoyo_globally_readable_list); +static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) +{ +	const u8 type = r->param.path_number.operation; +	u8 radix; +	const struct tomoyo_path_info *filename = r->param.path_number.filename; +	const char *operation = tomoyo_path_number_keyword[type]; +	char buffer[64]; +	if (r->granted) +		return 0; +	switch (type) { +	case TOMOYO_TYPE_CREATE: +	case TOMOYO_TYPE_MKDIR: +	case TOMOYO_TYPE_MKFIFO: +	case TOMOYO_TYPE_MKSOCK: +	case TOMOYO_TYPE_CHMOD: +		radix = TOMOYO_VALUE_TYPE_OCTAL; +		break; +	case TOMOYO_TYPE_IOCTL: +		radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; +		break; +	default: +		radix = TOMOYO_VALUE_TYPE_DECIMAL; +		break; +	} +	tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, +			   radix); +	tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer); +	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, +				 tomoyo_pattern(filename), buffer); +} + +static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a, +					  const struct tomoyo_acl_head *b) +{ +	return container_of(a, struct tomoyo_readable_file, +			    head)->filename == +		container_of(b, struct tomoyo_readable_file, +			     head)->filename; +}  /** - * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. + * tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list.   *   * @filename:  Filename unconditionally permitted to open() for reading.   * @is_delete: True if it is a delete request. @@ -195,41 +289,24 @@ LIST_HEAD(tomoyo_globally_readable_list);  static int tomoyo_update_globally_readable_entry(const char *filename,  						 const bool is_delete)  { -	struct tomoyo_globally_readable_file_entry *ptr; -	struct tomoyo_globally_readable_file_entry e = { }; -	int error = is_delete ? -ENOENT : -ENOMEM; +	struct tomoyo_readable_file e = { }; +	int error; -	if (!tomoyo_is_correct_path(filename, 1, 0, -1)) +	if (!tomoyo_correct_word(filename))  		return -EINVAL;  	e.filename = tomoyo_get_name(filename);  	if (!e.filename)  		return -ENOMEM; -	if (mutex_lock_interruptible(&tomoyo_policy_lock)) -		goto out; -	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { -		if (ptr->filename != e.filename) -			continue; -		ptr->is_deleted = is_delete; -		error = 0; -		break; -	} -	if (!is_delete && error) { -		struct tomoyo_globally_readable_file_entry *entry = -			tomoyo_commit_ok(&e, sizeof(e)); -		if (entry) { -			list_add_tail_rcu(&entry->list, -					  &tomoyo_globally_readable_list); -			error = 0; -		} -	} -	mutex_unlock(&tomoyo_policy_lock); - out: +	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, +				     &tomoyo_policy_list +				     [TOMOYO_ID_GLOBALLY_READABLE], +				     tomoyo_same_globally_readable);  	tomoyo_put_name(e.filename);  	return error;  }  /** - * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. + * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.   *   * @filename: The filename to check.   * @@ -237,14 +314,15 @@ static int tomoyo_update_globally_readable_entry(const char *filename,   *   * Caller holds tomoyo_read_lock().   */ -static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * +static bool tomoyo_globally_readable_file(const struct tomoyo_path_info *  					     filename)  { -	struct tomoyo_globally_readable_file_entry *ptr; +	struct tomoyo_readable_file *ptr;  	bool found = false; -	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { -		if (!ptr->is_deleted && +	list_for_each_entry_rcu(ptr, &tomoyo_policy_list +				[TOMOYO_ID_GLOBALLY_READABLE], head.list) { +		if (!ptr->head.is_deleted &&  		    tomoyo_path_matches_pattern(filename, ptr->filename)) {  			found = true;  			break; @@ -254,7 +332,7 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *  }  /** - * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. + * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list.   *   * @data:      String to parse.   * @is_delete: True if it is a delete request. @@ -263,74 +341,20 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *   *   * Caller holds tomoyo_read_lock().   */ -int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) +int tomoyo_write_globally_readable(char *data, const bool is_delete)  {  	return tomoyo_update_globally_readable_entry(data, is_delete);  } -/** - * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. - * - * @head: Pointer to "struct tomoyo_io_buffer". - * - * Returns true on success, false otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) +static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a, +				const struct tomoyo_acl_head *b)  { -	struct list_head *pos; -	bool done = true; - -	list_for_each_cookie(pos, head->read_var2, -			     &tomoyo_globally_readable_list) { -		struct tomoyo_globally_readable_file_entry *ptr; -		ptr = list_entry(pos, -				 struct tomoyo_globally_readable_file_entry, -				 list); -		if (ptr->is_deleted) -			continue; -		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", -					ptr->filename->name); -		if (!done) -			break; -	} -	return done; +	return container_of(a, struct tomoyo_no_pattern, head)->pattern == +		container_of(b, struct tomoyo_no_pattern, head)->pattern;  } -/* tomoyo_pattern_list is used for holding list of pathnames which are used for - * converting pathnames to pathname patterns during learning mode. - * - * An entry is added by - * - * # echo 'file_pattern /proc/\$/mounts' > \ - *                             /sys/kernel/security/tomoyo/exception_policy - * - * and is deleted by - * - * # echo 'delete file_pattern /proc/\$/mounts' > \ - *                             /sys/kernel/security/tomoyo/exception_policy - * - * and all entries are retrieved by - * - * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy - * - * In the example above, if a process which belongs to a domain which is in - * learning mode requested open("/proc/1/mounts", O_RDONLY), - * "allow_read /proc/\$/mounts" is automatically added to the domain which that - * process belongs to. - * - * It is not a desirable behavior that we have to use /proc/\$/ instead of - * /proc/self/ when current process needs to access only current process's - * information. As of now, LSM version of TOMOYO is using __d_path() for - * calculating pathname. Non LSM version of TOMOYO is using its own function - * which pretends as if /proc/self/ is not a symlink; so that we can forbid - * current process from accessing other process's information. - */ -LIST_HEAD(tomoyo_pattern_list); -  /** - * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. + * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list.   *   * @pattern:   Pathname pattern.   * @is_delete: True if it is a delete request. @@ -342,39 +366,23 @@ LIST_HEAD(tomoyo_pattern_list);  static int tomoyo_update_file_pattern_entry(const char *pattern,  					    const bool is_delete)  { -	struct tomoyo_pattern_entry *ptr; -	struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) }; -	int error = is_delete ? -ENOENT : -ENOMEM; +	struct tomoyo_no_pattern e = { }; +	int error; +	if (!tomoyo_correct_word(pattern)) +		return -EINVAL; +	e.pattern = tomoyo_get_name(pattern);  	if (!e.pattern) -		return error; -	if (!e.pattern->is_patterned) -		goto out; -	if (mutex_lock_interruptible(&tomoyo_policy_lock)) -		goto out; -	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { -		if (e.pattern != ptr->pattern) -			continue; -		ptr->is_deleted = is_delete; -		error = 0; -		break; -	} -	if (!is_delete && error) { -		struct tomoyo_pattern_entry *entry = -			tomoyo_commit_ok(&e, sizeof(e)); -		if (entry) { -			list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); -			error = 0; -		} -	} -	mutex_unlock(&tomoyo_policy_lock); - out: +		return -ENOMEM; +	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, +				     &tomoyo_policy_list[TOMOYO_ID_PATTERN], +				     tomoyo_same_pattern);  	tomoyo_put_name(e.pattern);  	return error;  }  /** - * tomoyo_get_file_pattern - Get patterned pathname. + * tomoyo_pattern - Get patterned pathname.   *   * @filename: The filename to find patterned pathname.   * @@ -382,14 +390,14 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,   *   * Caller holds tomoyo_read_lock().   */ -static const struct tomoyo_path_info * -tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) +const char *tomoyo_pattern(const struct tomoyo_path_info *filename)  { -	struct tomoyo_pattern_entry *ptr; +	struct tomoyo_no_pattern *ptr;  	const struct tomoyo_path_info *pattern = NULL; -	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { -		if (ptr->is_deleted) +	list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN], +				head.list) { +		if (ptr->head.is_deleted)  			continue;  		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))  			continue; @@ -403,11 +411,11 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)  	}  	if (pattern)  		filename = pattern; -	return filename; +	return filename->name;  }  /** - * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. + * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list.   *   * @data:      String to parse.   * @is_delete: True if it is a delete request. @@ -416,71 +424,21 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)   *   * Caller holds tomoyo_read_lock().   */ -int tomoyo_write_pattern_policy(char *data, const bool is_delete) +int tomoyo_write_pattern(char *data, const bool is_delete)  {  	return tomoyo_update_file_pattern_entry(data, is_delete);  } -/** - * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. - * - * @head: Pointer to "struct tomoyo_io_buffer". - * - * Returns true on success, false otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) +static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a, +				   const struct tomoyo_acl_head *b)  { -	struct list_head *pos; -	bool done = true; - -	list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { -		struct tomoyo_pattern_entry *ptr; -		ptr = list_entry(pos, struct tomoyo_pattern_entry, list); -		if (ptr->is_deleted) -			continue; -		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN -					"%s\n", ptr->pattern->name); -		if (!done) -			break; -	} -	return done; +	return container_of(a, struct tomoyo_no_rewrite, head)->pattern +		== container_of(b, struct tomoyo_no_rewrite, head) +		->pattern;  } -/* - * tomoyo_no_rewrite_list is used for holding list of pathnames which are by - * default forbidden to modify already written content of a file. - * - * An entry is added by - * - * # echo 'deny_rewrite /var/log/messages' > \ - *                              /sys/kernel/security/tomoyo/exception_policy - * - * and is deleted by - * - * # echo 'delete deny_rewrite /var/log/messages' > \ - *                              /sys/kernel/security/tomoyo/exception_policy - * - * and all entries are retrieved by - * - * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy - * - * In the example above, if a process requested to rewrite /var/log/messages , - * the process can't rewrite unless the domain which that process belongs to - * has "allow_rewrite /var/log/messages" entry. - * - * It is not a desirable behavior that we have to add "\040(deleted)" suffix - * when we want to allow rewriting already unlink()ed file. As of now, - * LSM version of TOMOYO is using __d_path() for calculating pathname. - * Non LSM version of TOMOYO is using its own function which doesn't append - * " (deleted)" suffix if the file is already unlink()ed; so that we don't - * need to worry whether the file is already unlink()ed or not. - */ -LIST_HEAD(tomoyo_no_rewrite_list); -  /** - * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. + * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list.   *   * @pattern:   Pathname pattern that are not rewritable by default.   * @is_delete: True if it is a delete request. @@ -492,41 +450,23 @@ LIST_HEAD(tomoyo_no_rewrite_list);  static int tomoyo_update_no_rewrite_entry(const char *pattern,  					  const bool is_delete)  { -	struct tomoyo_no_rewrite_entry *ptr; -	struct tomoyo_no_rewrite_entry e = { }; -	int error = is_delete ? -ENOENT : -ENOMEM; +	struct tomoyo_no_rewrite e = { }; +	int error; -	if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) +	if (!tomoyo_correct_word(pattern))  		return -EINVAL;  	e.pattern = tomoyo_get_name(pattern);  	if (!e.pattern) -		return error; -	if (mutex_lock_interruptible(&tomoyo_policy_lock)) -		goto out; -	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { -		if (ptr->pattern != e.pattern) -			continue; -		ptr->is_deleted = is_delete; -		error = 0; -		break; -	} -	if (!is_delete && error) { -		struct tomoyo_no_rewrite_entry *entry = -			tomoyo_commit_ok(&e, sizeof(e)); -		if (entry) { -			list_add_tail_rcu(&entry->list, -					  &tomoyo_no_rewrite_list); -			error = 0; -		} -	} -	mutex_unlock(&tomoyo_policy_lock); - out: +		return -ENOMEM; +	error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, +				     &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE], +				     tomoyo_same_no_rewrite);  	tomoyo_put_name(e.pattern);  	return error;  }  /** - * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. + * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.   *   * @filename: Filename to check.   * @@ -535,13 +475,14 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,   *   * Caller holds tomoyo_read_lock().   */ -static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) +static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename)  { -	struct tomoyo_no_rewrite_entry *ptr; +	struct tomoyo_no_rewrite *ptr;  	bool found = false; -	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { -		if (ptr->is_deleted) +	list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE], +				head.list) { +		if (ptr->head.is_deleted)  			continue;  		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))  			continue; @@ -552,7 +493,7 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)  }  /** - * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. + * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list.   *   * @data:      String to parse.   * @is_delete: True if it is a delete request. @@ -561,214 +502,103 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)   *   * Caller holds tomoyo_read_lock().   */ -int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) +int tomoyo_write_no_rewrite(char *data, const bool is_delete)  {  	return tomoyo_update_no_rewrite_entry(data, is_delete);  } -/** - * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. - * - * @head: Pointer to "struct tomoyo_io_buffer". - * - * Returns true on success, false otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) +static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, +				  const struct tomoyo_acl_info *ptr)  { -	struct list_head *pos; -	bool done = true; - -	list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { -		struct tomoyo_no_rewrite_entry *ptr; -		ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); -		if (ptr->is_deleted) -			continue; -		done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE -					"%s\n", ptr->pattern->name); -		if (!done) -			break; +	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), +							 head); +	if (acl->perm & (1 << r->param.path.operation)) { +		r->param.path.matched_path = +			tomoyo_compare_name_union(r->param.path.filename, +						  &acl->name); +		return r->param.path.matched_path != NULL;  	} -	return done; +	return false;  } -/** - * tomoyo_update_file_acl - Update file's read/write/execute ACL. - * - * @filename:  Filename. - * @perm:      Permission (between 1 to 7). - * @domain:    Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. - * - * Returns 0 on success, negative value otherwise. - * - * This is legacy support interface for older policy syntax. - * Current policy syntax uses "allow_read/write" instead of "6", - * "allow_read" instead of "4", "allow_write" instead of "2", - * "allow_execute" instead of "1". - * - * Caller holds tomoyo_read_lock(). - */ -static int tomoyo_update_file_acl(const char *filename, u8 perm, -				  struct tomoyo_domain_info * const domain, -				  const bool is_delete) +static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, +					 const struct tomoyo_acl_info *ptr)  { -	if (perm > 7 || !perm) { -		printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", -		       __func__, perm, filename); -		return -EINVAL; -	} -	if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) -		/* -		 * Only 'allow_mkdir' and 'allow_rmdir' are valid for -		 * directory permissions. -		 */ -		return 0; -	if (perm & 4) -		tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, -				       is_delete); -	if (perm & 2) -		tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, -				       is_delete); -	if (perm & 1) -		tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, -				       is_delete); -	return 0; +	const struct tomoyo_path_number_acl *acl = +		container_of(ptr, typeof(*acl), head); +	return (acl->perm & (1 << r->param.path_number.operation)) && +		tomoyo_compare_number_union(r->param.path_number.number, +					    &acl->number) && +		tomoyo_compare_name_union(r->param.path_number.filename, +					  &acl->name);  } -/** - * tomoyo_path_acl2 - Check permission for single path operation. - * - * @domain:          Pointer to "struct tomoyo_domain_info". - * @filename:        Filename to check. - * @perm:            Permission. - * @may_use_pattern: True if patterned ACL is permitted. - * - * Returns 0 on success, -EPERM otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain, -			    const struct tomoyo_path_info *filename, -			    const u32 perm, const bool may_use_pattern) +static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, +				   const struct tomoyo_acl_info *ptr)  { -	struct tomoyo_acl_info *ptr; -	int error = -EPERM; - -	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { -		struct tomoyo_path_acl *acl; -		if (ptr->type != TOMOYO_TYPE_PATH_ACL) -			continue; -		acl = container_of(ptr, struct tomoyo_path_acl, head); -		if (perm <= 0xFFFF) { -			if (!(acl->perm & perm)) -				continue; -		} else { -			if (!(acl->perm_high & (perm >> 16))) -				continue; -		} -		if (!tomoyo_compare_name_union_pattern(filename, &acl->name, -                                                       may_use_pattern)) -			continue; -		error = 0; -		break; -	} -	return error; +	const struct tomoyo_path2_acl *acl = +		container_of(ptr, typeof(*acl), head); +	return (acl->perm & (1 << r->param.path2.operation)) && +		tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) +		&& tomoyo_compare_name_union(r->param.path2.filename2, +					     &acl->name2);  } -/** - * tomoyo_check_file_acl - Check permission for opening files. - * - * @domain:    Pointer to "struct tomoyo_domain_info". - * @filename:  Filename to check. - * @operation: Mode ("read" or "write" or "read/write" or "execute"). - * - * Returns 0 on success, -EPERM otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, -				 const struct tomoyo_path_info *filename, -				 const u8 operation) +static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, +				const struct tomoyo_acl_info *ptr)  { -	u32 perm = 0; - -	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) -		return 0; -	if (operation == 6) -		perm = 1 << TOMOYO_TYPE_READ_WRITE; -	else if (operation == 4) -		perm = 1 << TOMOYO_TYPE_READ; -	else if (operation == 2) -		perm = 1 << TOMOYO_TYPE_WRITE; -	else if (operation == 1) -		perm = 1 << TOMOYO_TYPE_EXECUTE; -	else -		BUG(); -	return tomoyo_path_acl2(domain, filename, perm, operation != 1); +	const struct tomoyo_mkdev_acl *acl = +		container_of(ptr, typeof(*acl), head); +	return (acl->perm & (1 << r->param.mkdev.operation)) && +		tomoyo_compare_number_union(r->param.mkdev.mode, +					    &acl->mode) && +		tomoyo_compare_number_union(r->param.mkdev.major, +					    &acl->major) && +		tomoyo_compare_number_union(r->param.mkdev.minor, +					    &acl->minor) && +		tomoyo_compare_name_union(r->param.mkdev.filename, +					  &acl->name);  } -/** - * tomoyo_check_file_perm2 - Check permission for opening files. - * - * @domain:    Pointer to "struct tomoyo_domain_info". - * @filename:  Filename to check. - * @perm:      Mode ("read" or "write" or "read/write" or "execute"). - * @operation: Operation name passed used for verbose mode. - * @mode:      Access control mode. - * - * Returns 0 on success, negative value otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, -				   const struct tomoyo_path_info *filename, -				   const u8 perm, const char *operation, -				   const u8 mode) +static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, +				 const struct tomoyo_acl_info *b)  { -	const bool is_enforce = (mode == 3); -	const char *msg = "<unknown>"; -	int error = 0; +	const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); +	const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); +	return tomoyo_same_acl_head(&p1->head, &p2->head) && +		tomoyo_same_name_union(&p1->name, &p2->name); +} -	if (!filename) -		return 0; -	error = tomoyo_check_file_acl(domain, filename, perm); -	if (error && perm == 4 && !domain->ignore_global_allow_read -	    && tomoyo_is_globally_readable_file(filename)) -		error = 0; -	if (perm == 6) -		msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); -	else if (perm == 4) -		msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); -	else if (perm == 2) -		msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); -	else if (perm == 1) -		msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); -	else -		BUG(); -	if (!error) -		return 0; -	if (tomoyo_verbose_mode(domain)) -		printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied " -		       "for %s\n", tomoyo_get_msg(is_enforce), msg, operation, -		       filename->name, tomoyo_get_last_name(domain)); -	if (is_enforce) -		return error; -	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { -		/* Don't use patterns for execute permission. */ -		const struct tomoyo_path_info *patterned_file = (perm != 1) ? -			tomoyo_get_file_pattern(filename) : filename; -		tomoyo_update_file_acl(patterned_file->name, perm, -				       domain, false); +static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, +				  struct tomoyo_acl_info *b, +				  const bool is_delete) +{ +	u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) +		->perm; +	u16 perm = *a_perm; +	const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; +	if (is_delete) { +		perm &= ~b_perm; +		if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK) +			perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); +		else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE))) +			perm &= ~TOMOYO_RW_MASK; +	} else { +		perm |= b_perm; +		if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK) +			perm |= (1 << TOMOYO_TYPE_READ_WRITE); +		else if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) +			perm |= TOMOYO_RW_MASK;  	} -	return 0; +	*a_perm = perm; +	return !perm;  }  /** - * tomoyo_write_file_policy - Update file related list. + * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.   * - * @data:      String to parse. + * @type:      Type of operation. + * @filename:  Filename.   * @domain:    Pointer to "struct tomoyo_domain_info".   * @is_delete: True if it is a delete request.   * @@ -776,48 +606,65 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,   *   * Caller holds tomoyo_read_lock().   */ -int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, -			     const bool is_delete) +static int tomoyo_update_path_acl(const u8 type, const char *filename, +				  struct tomoyo_domain_info * const domain, +				  const bool is_delete)  { -	char *filename = strchr(data, ' '); -	char *filename2; -	unsigned int perm; -	u8 type; - -	if (!filename) +	struct tomoyo_path_acl e = { +		.head.type = TOMOYO_TYPE_PATH_ACL, +		.perm = 1 << type +	}; +	int error; +	if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE)) +		e.perm |= TOMOYO_RW_MASK; +	if (!tomoyo_parse_name_union(filename, &e.name))  		return -EINVAL; -	*filename++ = '\0'; -	if (sscanf(data, "%u", &perm) == 1) -		return tomoyo_update_file_acl(filename, (u8) perm, domain, -					      is_delete); -	if (strncmp(data, "allow_", 6)) -		goto out; -	data += 6; -	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { -		if (strcmp(data, tomoyo_path_keyword[type])) -			continue; -		return tomoyo_update_path_acl(type, filename, domain, -					      is_delete); -	} -	filename2 = strchr(filename, ' '); -	if (!filename2) -		goto out; -	*filename2++ = '\0'; -	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { -		if (strcmp(data, tomoyo_path2_keyword[type])) -			continue; -		return tomoyo_update_path2_acl(type, filename, filename2, -					       domain, is_delete); -	} - out: -	return -EINVAL; +	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, +				     tomoyo_same_path_acl, +				     tomoyo_merge_path_acl); +	tomoyo_put_name_union(&e.name); +	return error; +} + +static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, +					 const struct tomoyo_acl_info *b) +{ +	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), +								head); +	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), +								head); +	return tomoyo_same_acl_head(&p1->head, &p2->head) +		&& tomoyo_same_name_union(&p1->name, &p2->name) +		&& tomoyo_same_number_union(&p1->mode, &p2->mode) +		&& tomoyo_same_number_union(&p1->major, &p2->major) +		&& tomoyo_same_number_union(&p1->minor, &p2->minor); +} + +static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, +					  struct tomoyo_acl_info *b, +					  const bool is_delete) +{ +	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, +					 head)->perm; +	u8 perm = *a_perm; +	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) +		->perm; +	if (is_delete) +		perm &= ~b_perm; +	else +		perm |= b_perm; +	*a_perm = perm; +	return !perm;  }  /** - * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. + * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.   *   * @type:      Type of operation.   * @filename:  Filename. + * @mode:      Create mode. + * @major:     Device major number. + * @minor:     Device minor number.   * @domain:    Pointer to "struct tomoyo_domain_info".   * @is_delete: True if it is a delete request.   * @@ -825,71 +672,58 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,   *   * Caller holds tomoyo_read_lock().   */ -static int tomoyo_update_path_acl(const u8 type, const char *filename, -				  struct tomoyo_domain_info *const domain, -				  const bool is_delete) +static int tomoyo_update_mkdev_acl(const u8 type, const char *filename, +					  char *mode, char *major, char *minor, +					  struct tomoyo_domain_info * const +					  domain, const bool is_delete)  { -	static const u32 tomoyo_rw_mask = -		(1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); -	const u32 perm = 1 << type; -	struct tomoyo_acl_info *ptr; -	struct tomoyo_path_acl e = { -		.head.type = TOMOYO_TYPE_PATH_ACL, -		.perm_high = perm >> 16, -		.perm = perm +	struct tomoyo_mkdev_acl e = { +		.head.type = TOMOYO_TYPE_MKDEV_ACL, +		.perm = 1 << type  	};  	int error = is_delete ? -ENOENT : -ENOMEM; - -	if (type == TOMOYO_TYPE_READ_WRITE) -		e.perm |= tomoyo_rw_mask; -	if (!domain) -		return -EINVAL; -	if (!tomoyo_parse_name_union(filename, &e.name)) -		return -EINVAL; -	if (mutex_lock_interruptible(&tomoyo_policy_lock)) +	if (!tomoyo_parse_name_union(filename, &e.name) || +	    !tomoyo_parse_number_union(mode, &e.mode) || +	    !tomoyo_parse_number_union(major, &e.major) || +	    !tomoyo_parse_number_union(minor, &e.minor))  		goto out; -	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { -		struct tomoyo_path_acl *acl = -			container_of(ptr, struct tomoyo_path_acl, head); -		if (!tomoyo_is_same_path_acl(acl, &e)) -			continue; -		if (is_delete) { -			if (perm <= 0xFFFF) -				acl->perm &= ~perm; -			else -				acl->perm_high &= ~(perm >> 16); -			if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask) -				acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); -			else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) -				acl->perm &= ~tomoyo_rw_mask; -		} else { -			if (perm <= 0xFFFF) -				acl->perm |= perm; -			else -				acl->perm_high |= (perm >> 16); -			if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask) -				acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; -			else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) -				acl->perm |= tomoyo_rw_mask; -		} -		error = 0; -		break; -	} -	if (!is_delete && error) { -		struct tomoyo_path_acl *entry = -			tomoyo_commit_ok(&e, sizeof(e)); -		if (entry) { -			list_add_tail_rcu(&entry->head.list, -					  &domain->acl_info_list); -			error = 0; -		} -	} -	mutex_unlock(&tomoyo_policy_lock); +	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, +				     tomoyo_same_mkdev_acl, +				     tomoyo_merge_mkdev_acl);   out:  	tomoyo_put_name_union(&e.name); +	tomoyo_put_number_union(&e.mode); +	tomoyo_put_number_union(&e.major); +	tomoyo_put_number_union(&e.minor);  	return error;  } +static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, +				  const struct tomoyo_acl_info *b) +{ +	const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); +	const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); +	return tomoyo_same_acl_head(&p1->head, &p2->head) +		&& tomoyo_same_name_union(&p1->name1, &p2->name1) +		&& tomoyo_same_name_union(&p1->name2, &p2->name2); +} + +static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, +				   struct tomoyo_acl_info *b, +				   const bool is_delete) +{ +	u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) +		->perm; +	u8 perm = *a_perm; +	const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; +	if (is_delete) +		perm &= ~b_perm; +	else +		perm |= b_perm; +	*a_perm = perm; +	return !perm; +} +  /**   * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.   * @@ -905,46 +739,20 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,   */  static int tomoyo_update_path2_acl(const u8 type, const char *filename1,  				   const char *filename2, -				   struct tomoyo_domain_info *const domain, +				   struct tomoyo_domain_info * const domain,  				   const bool is_delete)  { -	const u8 perm = 1 << type;  	struct tomoyo_path2_acl e = {  		.head.type = TOMOYO_TYPE_PATH2_ACL, -		.perm = perm +		.perm = 1 << type  	}; -	struct tomoyo_acl_info *ptr;  	int error = is_delete ? -ENOENT : -ENOMEM; - -	if (!domain) -		return -EINVAL;  	if (!tomoyo_parse_name_union(filename1, &e.name1) ||  	    !tomoyo_parse_name_union(filename2, &e.name2))  		goto out; -	if (mutex_lock_interruptible(&tomoyo_policy_lock)) -		goto out; -	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { -		struct tomoyo_path2_acl *acl = -			container_of(ptr, struct tomoyo_path2_acl, head); -		if (!tomoyo_is_same_path2_acl(acl, &e)) -			continue; -		if (is_delete) -			acl->perm &= ~perm; -		else -			acl->perm |= perm; -		error = 0; -		break; -	} -	if (!is_delete && error) { -		struct tomoyo_path2_acl *entry = -			tomoyo_commit_ok(&e, sizeof(e)); -		if (entry) { -			list_add_tail_rcu(&entry->head.list, -					  &domain->acl_info_list); -			error = 0; -		} -	} -	mutex_unlock(&tomoyo_policy_lock); +	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, +				     tomoyo_same_path2_acl, +				     tomoyo_merge_path2_acl);   out:  	tomoyo_put_name_union(&e.name1);  	tomoyo_put_name_union(&e.name2); @@ -952,134 +760,158 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1,  }  /** - * tomoyo_path_acl - Check permission for single path operation. - * - * @domain:   Pointer to "struct tomoyo_domain_info". - * @type:     Type of operation. - * @filename: Filename to check. - * - * Returns 0 on success, negative value otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type, -			   const struct tomoyo_path_info *filename) -{ -	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) -		return 0; -	return tomoyo_path_acl2(domain, filename, 1 << type, 1); -} - -/** - * tomoyo_path2_acl - Check permission for double path operation. + * tomoyo_path_permission - Check permission for single path operation.   * - * @domain:    Pointer to "struct tomoyo_domain_info". - * @type:      Type of operation. - * @filename1: First filename to check. - * @filename2: Second filename to check. - * - * Returns 0 on success, -EPERM otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain, -			    const u8 type, -			    const struct tomoyo_path_info *filename1, -			    const struct tomoyo_path_info *filename2) -{ -	struct tomoyo_acl_info *ptr; -	const u8 perm = 1 << type; -	int error = -EPERM; - -	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) -		return 0; -	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { -		struct tomoyo_path2_acl *acl; -		if (ptr->type != TOMOYO_TYPE_PATH2_ACL) -			continue; -		acl = container_of(ptr, struct tomoyo_path2_acl, head); -		if (!(acl->perm & perm)) -			continue; -		if (!tomoyo_compare_name_union(filename1, &acl->name1)) -			continue; -		if (!tomoyo_compare_name_union(filename2, &acl->name2)) -			continue; -		error = 0; -		break; -	} -	return error; -} - -/** - * tomoyo_path_permission2 - Check permission for single path operation. - * - * @domain:    Pointer to "struct tomoyo_domain_info". + * @r:         Pointer to "struct tomoyo_request_info".   * @operation: Type of operation.   * @filename:  Filename to check. - * @mode:      Access control mode.   *   * Returns 0 on success, negative value otherwise.   *   * Caller holds tomoyo_read_lock().   */ -static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain, -				   u8 operation, -				   const struct tomoyo_path_info *filename, -				   const u8 mode) +int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, +			   const struct tomoyo_path_info *filename)  { -	const char *msg;  	int error; -	const bool is_enforce = (mode == 3); -	if (!mode) -		return 0;   next: -	error = tomoyo_path_acl(domain, operation, filename); -	msg = tomoyo_path2keyword(operation); -	if (!error) -		goto ok; -	if (tomoyo_verbose_mode(domain)) -		printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n", -		       tomoyo_get_msg(is_enforce), msg, filename->name, -		       tomoyo_get_last_name(domain)); -	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { -		const char *name = tomoyo_get_file_pattern(filename)->name; -		tomoyo_update_path_acl(operation, name, domain, false); -	} -	if (!is_enforce) -		error = 0; - ok: +	r->type = tomoyo_p2mac[operation]; +	r->mode = tomoyo_get_mode(r->profile, r->type); +	if (r->mode == TOMOYO_CONFIG_DISABLED) +		return 0; +	r->param_type = TOMOYO_TYPE_PATH_ACL; +	r->param.path.filename = filename; +	r->param.path.operation = operation; +	do { +		tomoyo_check_acl(r, tomoyo_check_path_acl); +		if (!r->granted && operation == TOMOYO_TYPE_READ && +		    !r->domain->ignore_global_allow_read && +		    tomoyo_globally_readable_file(filename)) +			r->granted = true; +		error = tomoyo_audit_path_log(r); +		/* +		 * Do not retry for execute request, for alias may have +		 * changed. +		 */ +	} while (error == TOMOYO_RETRY_REQUEST && +		 operation != TOMOYO_TYPE_EXECUTE);  	/*  	 * Since "allow_truncate" doesn't imply "allow_rewrite" permission,  	 * we need to check "allow_rewrite" permission if the filename is  	 * specified by "deny_rewrite" keyword.  	 */  	if (!error && operation == TOMOYO_TYPE_TRUNCATE && -	    tomoyo_is_no_rewrite_file(filename)) { +	    tomoyo_no_rewrite_file(filename)) {  		operation = TOMOYO_TYPE_REWRITE;  		goto next;  	}  	return error;  } +static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, +					const struct tomoyo_acl_info *b) +{ +	const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), +							       head); +	const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), +							       head); +	return tomoyo_same_acl_head(&p1->head, &p2->head) +		&& tomoyo_same_name_union(&p1->name, &p2->name) +		&& tomoyo_same_number_union(&p1->number, &p2->number); +} + +static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, +					 struct tomoyo_acl_info *b, +					 const bool is_delete) +{ +	u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, +					  head)->perm; +	u8 perm = *a_perm; +	const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) +		->perm; +	if (is_delete) +		perm &= ~b_perm; +	else +		perm |= b_perm; +	*a_perm = perm; +	return !perm; +} +  /** - * tomoyo_check_exec_perm - Check permission for "execute". + * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. + * + * @type:      Type of operation. + * @filename:  Filename. + * @number:    Number. + * @domain:    Pointer to "struct tomoyo_domain_info". + * @is_delete: True if it is a delete request.   * - * @domain:   Pointer to "struct tomoyo_domain_info". - * @filename: Check permission for "execute". + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_update_path_number_acl(const u8 type, const char *filename, +					 char *number, +					 struct tomoyo_domain_info * const +					 domain, +					 const bool is_delete) +{ +	struct tomoyo_path_number_acl e = { +		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, +		.perm = 1 << type +	}; +	int error = is_delete ? -ENOENT : -ENOMEM; +	if (!tomoyo_parse_name_union(filename, &e.name)) +		return -EINVAL; +	if (!tomoyo_parse_number_union(number, &e.number)) +		goto out; +	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, +				     tomoyo_same_path_number_acl, +				     tomoyo_merge_path_number_acl); + out: +	tomoyo_put_name_union(&e.name); +	tomoyo_put_number_union(&e.number); +	return error; +} + +/** + * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".   * - * Returns 0 on success, negativevalue otherwise. + * @type:   Type of operation. + * @path:   Pointer to "struct path". + * @number: Number.   * - * Caller holds tomoyo_read_lock(). + * Returns 0 on success, negative value otherwise.   */ -int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, -			   const struct tomoyo_path_info *filename) +int tomoyo_path_number_perm(const u8 type, struct path *path, +			    unsigned long number)  { -	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); +	struct tomoyo_request_info r; +	int error = -ENOMEM; +	struct tomoyo_path_info buf; +	int idx; -	if (!mode) +	if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) +	    == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)  		return 0; -	return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode); +	idx = tomoyo_read_lock(); +	if (!tomoyo_get_realpath(&buf, path)) +		goto out; +	if (type == TOMOYO_TYPE_MKDIR) +		tomoyo_add_slash(&buf); +	r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; +	r.param.path_number.operation = type; +	r.param.path_number.filename = &buf; +	r.param.path_number.number = number; +	do { +		tomoyo_check_acl(&r, tomoyo_check_path_number_acl); +		error = tomoyo_audit_path_number_log(&r); +	} while (error == TOMOYO_RETRY_REQUEST); +	kfree(buf.name); + out: +	tomoyo_read_unlock(idx); +	if (r.mode != TOMOYO_CONFIG_ENFORCING) +		error = 0; +	return error;  }  /** @@ -1096,24 +928,17 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,  {  	const u8 acc_mode = ACC_MODE(flag);  	int error = -ENOMEM; -	struct tomoyo_path_info *buf; -	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); -	const bool is_enforce = (mode == 3); +	struct tomoyo_path_info buf; +	struct tomoyo_request_info r;  	int idx; -	if (!mode || !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(); -	buf = tomoyo_get_path(path); -	if (!buf) +	if (!tomoyo_get_realpath(&buf, path))  		goto out;  	error = 0;  	/* @@ -1121,28 +946,43 @@ 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_permission2(domain, TOMOYO_TYPE_REWRITE, -						buf, mode); +	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_no_rewrite_file(&buf)) +			error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, +						       &buf); +	} +	if (!error && acc_mode && +	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) +	    != TOMOYO_CONFIG_DISABLED) { +		u8 operation; +		if (!buf.name && !tomoyo_get_realpath(&buf, path)) { +			error = -ENOMEM; +			goto out; +		} +		if (acc_mode == (MAY_READ | MAY_WRITE)) +			operation = TOMOYO_TYPE_READ_WRITE; +		else if (acc_mode == MAY_READ) +			operation = TOMOYO_TYPE_READ; +		else +			operation = TOMOYO_TYPE_WRITE; +		error = tomoyo_path_permission(&r, operation, &buf);  	} -	if (!error) -		error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", -						mode); -	if (!error && (flag & O_TRUNC)) -		error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE, -						buf, mode);   out: -	kfree(buf); +	kfree(buf.name);  	tomoyo_read_unlock(idx); -	if (!is_enforce) +	if (r.mode != TOMOYO_CONFIG_ENFORCING)  		error = 0;  	return error;  }  /** - * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". + * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".   *   * @operation: Type of operation.   * @path:      Pointer to "struct path". @@ -1152,71 +992,79 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,  int tomoyo_path_perm(const u8 operation, struct path *path)  {  	int error = -ENOMEM; -	struct tomoyo_path_info *buf; -	struct tomoyo_domain_info *domain = tomoyo_domain(); -	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); -	const bool is_enforce = (mode == 3); +	struct tomoyo_path_info buf; +	struct tomoyo_request_info r;  	int idx; -	if (!mode || !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(); -	buf = tomoyo_get_path(path); -	if (!buf) +	if (!tomoyo_get_realpath(&buf, path))  		goto out;  	switch (operation) { -	case TOMOYO_TYPE_MKDIR: +	case TOMOYO_TYPE_REWRITE: +		if (!tomoyo_no_rewrite_file(&buf)) { +			error = 0; +			goto out; +		} +		break;  	case TOMOYO_TYPE_RMDIR:  	case TOMOYO_TYPE_CHROOT: -		if (!buf->is_dir) { -			/* -			 * tomoyo_get_path() reserves space for appending "/." -			 */ -			strcat((char *) buf->name, "/"); -			tomoyo_fill_path_info(buf); -		} +	case TOMOYO_TYPE_UMOUNT: +		tomoyo_add_slash(&buf); +		break;  	} -	error = tomoyo_path_permission2(domain, operation, buf, mode); +	error = tomoyo_path_permission(&r, operation, &buf);   out: -	kfree(buf); +	kfree(buf.name);  	tomoyo_read_unlock(idx); -	if (!is_enforce) +	if (r.mode != TOMOYO_CONFIG_ENFORCING)  		error = 0;  	return error;  }  /** - * tomoyo_check_rewrite_permission - Check permission for "rewrite". + * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".   * - * @filp: Pointer to "struct file". + * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) + * @path:      Pointer to "struct path". + * @mode:      Create mode. + * @dev:       Device number.   *   * Returns 0 on success, negative value otherwise.   */ -int tomoyo_check_rewrite_permission(struct file *filp) +int tomoyo_mkdev_perm(const u8 operation, struct path *path, +			     const unsigned int mode, unsigned int dev)  { +	struct tomoyo_request_info r;  	int error = -ENOMEM; -	struct tomoyo_domain_info *domain = tomoyo_domain(); -	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); -	const bool is_enforce = (mode == 3); -	struct tomoyo_path_info *buf; +	struct tomoyo_path_info buf;  	int idx; -	if (!mode || !filp->f_path.mnt) +	if (!path->mnt || +	    tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) +	    == TOMOYO_CONFIG_DISABLED)  		return 0; -  	idx = tomoyo_read_lock(); -	buf = tomoyo_get_path(&filp->f_path); -	if (!buf) -		goto out; -	if (!tomoyo_is_no_rewrite_file(buf)) { -		error = 0; -		goto out; +	error = -ENOMEM; +	if (tomoyo_get_realpath(&buf, path)) { +		dev = new_decode_dev(dev); +		r.param_type = TOMOYO_TYPE_MKDEV_ACL; +		r.param.mkdev.filename = &buf; +		r.param.mkdev.operation = operation; +		r.param.mkdev.mode = mode; +		r.param.mkdev.major = MAJOR(dev); +		r.param.mkdev.minor = MINOR(dev); +		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl); +		error = tomoyo_audit_mkdev_log(&r); +		kfree(buf.name);  	} -	error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode); - out: -	kfree(buf);  	tomoyo_read_unlock(idx); -	if (!is_enforce) +	if (r.mode != TOMOYO_CONFIG_ENFORCING)  		error = 0;  	return error;  } @@ -1234,56 +1082,99 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,  		      struct path *path2)  {  	int error = -ENOMEM; -	struct tomoyo_path_info *buf1, *buf2; -	struct tomoyo_domain_info *domain = tomoyo_domain(); -	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); -	const bool is_enforce = (mode == 3); -	const char *msg; +	struct tomoyo_path_info buf1; +	struct tomoyo_path_info buf2; +	struct tomoyo_request_info r;  	int idx; -	if (!mode || !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;  	idx = tomoyo_read_lock(); -	buf1 = tomoyo_get_path(path1); -	buf2 = tomoyo_get_path(path2); -	if (!buf1 || !buf2) -		goto out; -	{ -		struct dentry *dentry = path1->dentry; -		if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { -			/* -			 * tomoyo_get_path() reserves space for appending "/." -			 */ -			if (!buf1->is_dir) { -				strcat((char *) buf1->name, "/"); -				tomoyo_fill_path_info(buf1); -			} -			if (!buf2->is_dir) { -				strcat((char *) buf2->name, "/"); -				tomoyo_fill_path_info(buf2); -			} -		} -	} -	error = tomoyo_path2_acl(domain, operation, buf1, buf2); -	msg = tomoyo_path22keyword(operation); -	if (!error) +	if (!tomoyo_get_realpath(&buf1, path1) || +	    !tomoyo_get_realpath(&buf2, path2))  		goto out; -	if (tomoyo_verbose_mode(domain)) -		printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' " -		       "denied for %s\n", tomoyo_get_msg(is_enforce), -		       msg, buf1->name, buf2->name, -		       tomoyo_get_last_name(domain)); -	if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { -		const char *name1 = tomoyo_get_file_pattern(buf1)->name; -		const char *name2 = tomoyo_get_file_pattern(buf2)->name; -		tomoyo_update_path2_acl(operation, name1, name2, domain, -					false); -	} +	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; +        } +	r.param_type = TOMOYO_TYPE_PATH2_ACL; +	r.param.path2.operation = operation; +	r.param.path2.filename1 = &buf1; +	r.param.path2.filename2 = &buf2; +	do { +		tomoyo_check_acl(&r, tomoyo_check_path2_acl); +		error = tomoyo_audit_path2_log(&r); +	} while (error == TOMOYO_RETRY_REQUEST);   out: -	kfree(buf1); -	kfree(buf2); +	kfree(buf1.name); +	kfree(buf2.name);  	tomoyo_read_unlock(idx); -	if (!is_enforce) +	if (r.mode != TOMOYO_CONFIG_ENFORCING)  		error = 0;  	return error;  } + +/** + * tomoyo_write_file - Update file related list. + * + * @data:      String to parse. + * @domain:    Pointer to "struct tomoyo_domain_info". + * @is_delete: True if it is a delete request. + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain, +		      const bool is_delete) +{ +	char *w[5]; +	u8 type; +	if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) +		return -EINVAL; +	if (strncmp(w[0], "allow_", 6)) +		goto out; +	w[0] += 6; +	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { +		if (strcmp(w[0], tomoyo_path_keyword[type])) +			continue; +		return tomoyo_update_path_acl(type, w[1], domain, is_delete); +	} +	if (!w[2][0]) +		goto out; +	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { +		if (strcmp(w[0], tomoyo_path2_keyword[type])) +			continue; +		return tomoyo_update_path2_acl(type, w[1], w[2], domain, +					       is_delete); +	} +	for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { +		if (strcmp(w[0], tomoyo_path_number_keyword[type])) +			continue; +		return tomoyo_update_path_number_acl(type, w[1], w[2], domain, +						     is_delete); +	} +	if (!w[3][0] || !w[4][0]) +		goto out; +	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) { +		if (strcmp(w[0], tomoyo_mkdev_keyword[type])) +			continue; +		return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3], +					       w[4], domain, is_delete); +	} + out: +	return -EINVAL; +}  | 
