TOMOYO: Cleanup part 1.

In order to synchronize with TOMOYO 1.8's syntax,

(1) Remove special handling for allow_read/write permission.
(2) Replace deny_rewrite/allow_rewrite permission with allow_append permission.
(3) Remove file_pattern keyword.
(4) Remove allow_read permission from exception policy.
(5) Allow creating domains in enforcing mode without calling supervisor.
(6) Add permission check for opening directory for reading.
(7) Add permission check for stat() operation.
(8) Make "cat < /sys/kernel/security/tomoyo/self_domain" behave as if
    "cat /sys/kernel/security/tomoyo/self_domain".

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index a0d09e5..0776173 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -39,13 +39,13 @@
 	[TOMOYO_MAC_FILE_OPEN]       = "file::open",
 	[TOMOYO_MAC_FILE_CREATE]     = "file::create",
 	[TOMOYO_MAC_FILE_UNLINK]     = "file::unlink",
+	[TOMOYO_MAC_FILE_GETATTR]    = "file::getattr",
 	[TOMOYO_MAC_FILE_MKDIR]      = "file::mkdir",
 	[TOMOYO_MAC_FILE_RMDIR]      = "file::rmdir",
 	[TOMOYO_MAC_FILE_MKFIFO]     = "file::mkfifo",
 	[TOMOYO_MAC_FILE_MKSOCK]     = "file::mksock",
 	[TOMOYO_MAC_FILE_TRUNCATE]   = "file::truncate",
 	[TOMOYO_MAC_FILE_SYMLINK]    = "file::symlink",
-	[TOMOYO_MAC_FILE_REWRITE]    = "file::rewrite",
 	[TOMOYO_MAC_FILE_MKBLOCK]    = "file::mkblock",
 	[TOMOYO_MAC_FILE_MKCHAR]     = "file::mkchar",
 	[TOMOYO_MAC_FILE_LINK]       = "file::link",
@@ -881,10 +881,6 @@
 			domain->profile = (u8) profile;
 		return 0;
 	}
-	if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
-		domain->ignore_global_allow_read = !is_delete;
-		return 0;
-	}
 	if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) {
 		domain->quota_warned = !is_delete;
 		return 0;
@@ -942,11 +938,6 @@
 			if (head->r.print_execute_only &&
 			    bit != TOMOYO_TYPE_EXECUTE)
 				continue;
-			/* Print "read/write" instead of "read" and "write". */
-			if ((bit == TOMOYO_TYPE_READ ||
-			     bit == TOMOYO_TYPE_WRITE)
-			    && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
-				continue;
 			break;
 		}
 		if (bit >= TOMOYO_MAX_PATH_OPERATION)
@@ -1055,10 +1046,6 @@
 				tomoyo_set_string(head, "quota_exceeded\n");
 			if (domain->transition_failed)
 				tomoyo_set_string(head, "transition_failed\n");
-			if (domain->ignore_global_allow_read)
-				tomoyo_set_string(head,
-				       TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ
-						  "\n");
 			head->r.step++;
 			tomoyo_set_lf(head);
 			/* fall through */
@@ -1235,18 +1222,15 @@
 	static const struct {
 		const char *keyword;
 		int (*write) (char *, const bool);
-	} tomoyo_callback[4] = {
+	} tomoyo_callback[1] = {
 		{ TOMOYO_KEYWORD_AGGREGATOR, tomoyo_write_aggregator },
-		{ TOMOYO_KEYWORD_FILE_PATTERN, tomoyo_write_pattern },
-		{ TOMOYO_KEYWORD_DENY_REWRITE, tomoyo_write_no_rewrite },
-		{ TOMOYO_KEYWORD_ALLOW_READ, tomoyo_write_globally_readable },
 	};
 
 	for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
 		if (tomoyo_str_starts(&data, tomoyo_transition_type[i]))
 			return tomoyo_write_transition_control(data, is_delete,
 							       i);
-	for (i = 0; i < 4; i++)
+	for (i = 0; i < 1; i++)
 		if (tomoyo_str_starts(&data, tomoyo_callback[i].keyword))
 			return tomoyo_callback[i].write(data, is_delete);
 	for (i = 0; i < TOMOYO_MAX_GROUP; i++)
@@ -1336,15 +1320,6 @@
 							  name);
 			}
 			break;
-		case TOMOYO_ID_GLOBALLY_READABLE:
-			{
-				struct tomoyo_readable_file *ptr =
-					container_of(acl, typeof(*ptr), head);
-				tomoyo_set_string(head,
-						  TOMOYO_KEYWORD_ALLOW_READ);
-				tomoyo_set_string(head, ptr->filename->name);
-			}
-			break;
 		case TOMOYO_ID_AGGREGATOR:
 			{
 				struct tomoyo_aggregator *ptr =
@@ -1358,24 +1333,6 @@
 					       ptr->aggregated_name->name);
 			}
 			break;
-		case TOMOYO_ID_PATTERN:
-			{
-				struct tomoyo_no_pattern *ptr =
-					container_of(acl, typeof(*ptr), head);
-				tomoyo_set_string(head,
-						  TOMOYO_KEYWORD_FILE_PATTERN);
-				tomoyo_set_string(head, ptr->pattern->name);
-			}
-			break;
-		case TOMOYO_ID_NO_REWRITE:
-			{
-				struct tomoyo_no_rewrite *ptr =
-					container_of(acl, typeof(*ptr), head);
-				tomoyo_set_string(head,
-						  TOMOYO_KEYWORD_DENY_REWRITE);
-				tomoyo_set_string(head, ptr->pattern->name);
-			}
-			break;
 		default:
 			continue;
 		}
@@ -1891,21 +1848,12 @@
 		head->reader_idx = tomoyo_read_lock();
 	file->private_data = head;
 	/*
-	 * Call the handler now if the file is
-	 * /sys/kernel/security/tomoyo/self_domain
-	 * so that the user can use
-	 * cat < /sys/kernel/security/tomoyo/self_domain"
-	 * to know the current process's domainname.
-	 */
-	if (type == TOMOYO_SELFDOMAIN)
-		tomoyo_read_control(file, NULL, 0);
-	/*
 	 * If the file is /sys/kernel/security/tomoyo/query , increment the
 	 * observer counter.
 	 * The obserber counter is used by tomoyo_supervisor() to see if
 	 * there is some process monitoring /sys/kernel/security/tomoyo/query.
 	 */
-	else if (type == TOMOYO_QUERY)
+	if (type == TOMOYO_QUERY)
 		atomic_inc(&tomoyo_query_observers);
 	return 0;
 }
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 7c66bd8..a5d6e21 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -52,9 +52,6 @@
 	TOMOYO_ID_NUMBER_GROUP,
 	TOMOYO_ID_TRANSITION_CONTROL,
 	TOMOYO_ID_AGGREGATOR,
-	TOMOYO_ID_GLOBALLY_READABLE,
-	TOMOYO_ID_PATTERN,
-	TOMOYO_ID_NO_REWRITE,
 	TOMOYO_ID_MANAGER,
 	TOMOYO_ID_NAME,
 	TOMOYO_ID_ACL,
@@ -73,8 +70,6 @@
 #define TOMOYO_KEYWORD_ALLOW_MOUNT               "allow_mount "
 #define TOMOYO_KEYWORD_ALLOW_READ                "allow_read "
 #define TOMOYO_KEYWORD_DELETE                    "delete "
-#define TOMOYO_KEYWORD_DENY_REWRITE              "deny_rewrite "
-#define TOMOYO_KEYWORD_FILE_PATTERN              "file_pattern "
 #define TOMOYO_KEYWORD_INITIALIZE_DOMAIN         "initialize_domain "
 #define TOMOYO_KEYWORD_KEEP_DOMAIN               "keep_domain "
 #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN      "no_initialize_domain "
@@ -83,7 +78,6 @@
 #define TOMOYO_KEYWORD_NUMBER_GROUP              "number_group "
 #define TOMOYO_KEYWORD_SELECT                    "select "
 #define TOMOYO_KEYWORD_USE_PROFILE               "use_profile "
-#define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ  "ignore_global_allow_read"
 #define TOMOYO_KEYWORD_QUOTA_EXCEEDED            "quota_exceeded"
 #define TOMOYO_KEYWORD_TRANSITION_FAILED         "transition_failed"
 /* A domain definition starts with <kernel>. */
@@ -115,35 +109,21 @@
 };
 
 /* Index numbers for File Controls. */
-
-/*
- * TOMOYO_TYPE_READ_WRITE is special. TOMOYO_TYPE_READ_WRITE is automatically
- * set if both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are set.
- * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically set if
- * TOMOYO_TYPE_READ_WRITE is set.
- * TOMOYO_TYPE_READ_WRITE is automatically cleared if either TOMOYO_TYPE_READ
- * or TOMOYO_TYPE_WRITE is cleared.
- * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically cleared if
- * TOMOYO_TYPE_READ_WRITE is cleared.
- */
-
 enum tomoyo_path_acl_index {
-	TOMOYO_TYPE_READ_WRITE,
 	TOMOYO_TYPE_EXECUTE,
 	TOMOYO_TYPE_READ,
 	TOMOYO_TYPE_WRITE,
+	TOMOYO_TYPE_APPEND,
 	TOMOYO_TYPE_UNLINK,
+	TOMOYO_TYPE_GETATTR,
 	TOMOYO_TYPE_RMDIR,
 	TOMOYO_TYPE_TRUNCATE,
 	TOMOYO_TYPE_SYMLINK,
-	TOMOYO_TYPE_REWRITE,
 	TOMOYO_TYPE_CHROOT,
 	TOMOYO_TYPE_UMOUNT,
 	TOMOYO_MAX_PATH_OPERATION
 };
 
-#define TOMOYO_RW_MASK ((1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE))
-
 enum tomoyo_mkdev_acl_index {
 	TOMOYO_TYPE_MKBLOCK,
 	TOMOYO_TYPE_MKCHAR,
@@ -187,13 +167,13 @@
 	TOMOYO_MAC_FILE_OPEN,
 	TOMOYO_MAC_FILE_CREATE,
 	TOMOYO_MAC_FILE_UNLINK,
+	TOMOYO_MAC_FILE_GETATTR,
 	TOMOYO_MAC_FILE_MKDIR,
 	TOMOYO_MAC_FILE_RMDIR,
 	TOMOYO_MAC_FILE_MKFIFO,
 	TOMOYO_MAC_FILE_MKSOCK,
 	TOMOYO_MAC_FILE_TRUNCATE,
 	TOMOYO_MAC_FILE_SYMLINK,
-	TOMOYO_MAC_FILE_REWRITE,
 	TOMOYO_MAC_FILE_MKBLOCK,
 	TOMOYO_MAC_FILE_MKCHAR,
 	TOMOYO_MAC_FILE_LINK,
@@ -388,9 +368,7 @@
  *      "deleted", false otherwise.
  *  (6) "quota_warned" is a bool which is used for suppressing warning message
  *      when learning mode learned too much entries.
- *  (7) "ignore_global_allow_read" is a bool which is true if this domain
- *      should ignore "allow_read" directive in exception policy.
- *  (8) "transition_failed" is a bool which is set to true when this domain was
+ *  (7) "transition_failed" is a bool which is set to true when this domain was
  *      unable to create a new domain at tomoyo_find_next_domain() because the
  *      name of the domain to be created was too long or it could not allocate
  *      memory. If set to true, more than one process continued execve()
@@ -415,7 +393,6 @@
 	u8 profile;        /* Profile number to use. */
 	bool is_deleted;   /* Delete flag.           */
 	bool quota_warned; /* Quota warnning flag.   */
-	bool ignore_global_allow_read; /* Ignore "allow_read" flag. */
 	bool transition_failed; /* Domain transition failed flag. */
 	atomic_t users; /* Number of referring credentials. */
 };
@@ -429,10 +406,9 @@
  *  (2) "perm" which is a bitmask of permitted operations.
  *  (3) "name" is the pathname.
  *
- * Directives held by this structure are "allow_read/write", "allow_execute",
- * "allow_read", "allow_write", "allow_unlink", "allow_rmdir",
- * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_chroot" and
- * "allow_unmount".
+ * Directives held by this structure are "allow_execute", "allow_read",
+ * "allow_write", "allow_append", "allow_unlink", "allow_rmdir",
+ * "allow_truncate", "allow_symlink", "allow_chroot" and "allow_unmount".
  */
 struct tomoyo_path_acl {
 	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */
@@ -574,47 +550,6 @@
 };
 
 /*
- * tomoyo_readable_file is a structure which is used for holding
- * "allow_read" entries.
- * It has following fields.
- *
- *  (1) "head" is "struct tomoyo_acl_head".
- *  (2) "filename" is a pathname which is allowed to open(O_RDONLY).
- */
-struct tomoyo_readable_file {
-	struct tomoyo_acl_head head;
-	const struct tomoyo_path_info *filename;
-};
-
-/*
- * tomoyo_no_pattern is a structure which is used for holding
- * "file_pattern" entries.
- * It has following fields.
- *
- *  (1) "head" is "struct tomoyo_acl_head".
- *  (2) "pattern" is a pathname pattern which is used for converting pathnames
- *      to pathname patterns during learning mode.
- */
-struct tomoyo_no_pattern {
-	struct tomoyo_acl_head head;
-	const struct tomoyo_path_info *pattern;
-};
-
-/*
- * tomoyo_no_rewrite is a structure which is used for holding
- * "deny_rewrite" entries.
- * It has following fields.
- *
- *  (1) "head" is "struct tomoyo_acl_head".
- *  (2) "pattern" is a pathname which is by default not permitted to modify
- *      already existing content.
- */
-struct tomoyo_no_rewrite {
-	struct tomoyo_acl_head head;
-	const struct tomoyo_path_info *pattern;
-};
-
-/*
  * tomoyo_transition_control is a structure which is used for holding
  * "initialize_domain"/"no_initialize_domain"/"keep_domain"/"no_keep_domain"
  * entries.
@@ -764,23 +699,17 @@
 int tomoyo_write_transition_control(char *data, const bool is_delete,
 				    const u8 type);
 /*
- * Create "allow_read/write", "allow_execute", "allow_read", "allow_write",
+ * Create "allow_execute", "allow_read", "allow_write", "allow_append",
  * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
  * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar",
- * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_rename" and
- * "allow_link" entry in domain policy.
+ * "allow_truncate", "allow_symlink", "allow_rename" and "allow_link" entry
+ * in domain policy.
  */
 int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
 		      const bool is_delete);
-/* Create "allow_read" entry in exception policy. */
-int tomoyo_write_globally_readable(char *data, const bool is_delete);
 /* Create "allow_mount" entry in domain policy. */
 int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
 		       const bool is_delete);
-/* Create "deny_rewrite" entry in exception policy. */
-int tomoyo_write_no_rewrite(char *data, const bool is_delete);
-/* Create "file_pattern" entry in exception policy. */
-int tomoyo_write_pattern(char *data, const bool is_delete);
 /* Create "path_group"/"number_group" entry in exception policy. */
 int tomoyo_write_group(char *data, const bool is_delete, const u8 type);
 int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
@@ -819,8 +748,6 @@
  * ignores chroot'ed root and the pathname is already solved.
  */
 char *tomoyo_realpath_from_path(struct path *path);
-/* Get patterned pathname. */
-const char *tomoyo_pattern(const struct tomoyo_path_info *filename);
 
 /* Check memory quota. */
 bool tomoyo_memory_ok(void *ptr);
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index 3538840..355b536 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -510,17 +510,8 @@
 	if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
 		goto done;
 	domain = tomoyo_find_domain(tmp);
-	if (domain)
-		goto done;
-	if (is_enforce) {
-		int error = tomoyo_supervisor(&r, "# wants to create domain\n"
-					      "%s\n", tmp);
-		if (error == TOMOYO_RETRY_REQUEST)
-			goto retry;
-		if (error < 0)
-			goto done;
-	}
-	domain = tomoyo_assign_domain(tmp, old_domain->profile);
+	if (!domain)
+		domain = tomoyo_assign_domain(tmp, old_domain->profile);
  done:
 	if (domain)
 		goto out;
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index d64e8ec..41ed7de 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -11,15 +11,15 @@
 
 /* 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_APPEND]     = "append",
 	[TOMOYO_TYPE_UNLINK]     = "unlink",
+	[TOMOYO_TYPE_GETATTR]    = "getattr",
 	[TOMOYO_TYPE_RMDIR]      = "rmdir",
 	[TOMOYO_TYPE_TRUNCATE]   = "truncate",
 	[TOMOYO_TYPE_SYMLINK]    = "symlink",
-	[TOMOYO_TYPE_REWRITE]    = "rewrite",
 	[TOMOYO_TYPE_CHROOT]     = "chroot",
 	[TOMOYO_TYPE_UMOUNT]     = "unmount",
 };
@@ -50,15 +50,15 @@
 };
 
 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_APPEND]     = TOMOYO_MAC_FILE_OPEN,
 	[TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
+	[TOMOYO_TYPE_GETATTR]    = TOMOYO_MAC_FILE_GETATTR,
 	[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,
 };
@@ -132,24 +132,6 @@
 }
 
 /**
- * tomoyo_strendswith - Check whether the token ends with the given token.
- *
- * @name: The token to check.
- * @tail: The token to find.
- *
- * Returns true if @name ends with @tail, false otherwise.
- */
-static bool tomoyo_strendswith(const char *name, const char *tail)
-{
-	int len;
-
-	if (!name || !tail)
-		return false;
-	len = strlen(name) - strlen(tail);
-	return len >= 0 && !strcmp(name + len, tail);
-}
-
-/**
  * tomoyo_get_realpath - Get realpath.
  *
  * @buf:  Pointer to "struct tomoyo_path_info".
@@ -182,7 +164,7 @@
 		return 0;
 	tomoyo_warn_log(r, "%s %s", operation, filename->name);
 	return tomoyo_supervisor(r, "allow_%s %s\n", operation,
-				 tomoyo_pattern(filename));
+				 filename->name);
 }
 
 /**
@@ -202,8 +184,7 @@
 	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));
+				 filename1->name, filename2->name);
 }
 
 /**
@@ -225,7 +206,7 @@
 	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);
+				 filename->name, mode, major, minor);
 }
 
 /**
@@ -264,247 +245,7 @@
 			   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_readable_file" list.
- *
- * @filename:  Filename unconditionally permitted to open() for reading.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_globally_readable_entry(const char *filename,
-						 const bool is_delete)
-{
-	struct tomoyo_readable_file e = { };
-	int error;
-
-	if (!tomoyo_correct_word(filename))
-		return -EINVAL;
-	e.filename = tomoyo_get_name(filename);
-	if (!e.filename)
-		return -ENOMEM;
-	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_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
- *
- * @filename: The filename to check.
- *
- * Returns true if any domain can open @filename for reading, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static bool tomoyo_globally_readable_file(const struct tomoyo_path_info *
-					     filename)
-{
-	struct tomoyo_readable_file *ptr;
-	bool found = false;
-
-	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;
-		}
-	}
-	return found;
-}
-
-/**
- * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list.
- *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_globally_readable(char *data, const bool is_delete)
-{
-	return tomoyo_update_globally_readable_entry(data, is_delete);
-}
-
-static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a,
-				const struct tomoyo_acl_head *b)
-{
-	return container_of(a, struct tomoyo_no_pattern, head)->pattern ==
-		container_of(b, struct tomoyo_no_pattern, head)->pattern;
-}
-
-/**
- * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list.
- *
- * @pattern:   Pathname pattern.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_file_pattern_entry(const char *pattern,
-					    const bool is_delete)
-{
-	struct tomoyo_no_pattern e = { };
-	int error;
-
-	if (!tomoyo_correct_word(pattern))
-		return -EINVAL;
-	e.pattern = tomoyo_get_name(pattern);
-	if (!e.pattern)
-		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_pattern - Get patterned pathname.
- *
- * @filename: The filename to find patterned pathname.
- *
- * Returns pointer to pathname pattern if matched, @filename otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-const char *tomoyo_pattern(const struct tomoyo_path_info *filename)
-{
-	struct tomoyo_no_pattern *ptr;
-	const struct tomoyo_path_info *pattern = NULL;
-
-	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;
-		pattern = ptr->pattern;
-		if (tomoyo_strendswith(pattern->name, "/\\*")) {
-			/* Do nothing. Try to find the better match. */
-		} else {
-			/* This would be the better match. Use this. */
-			break;
-		}
-	}
-	if (pattern)
-		filename = pattern;
-	return filename->name;
-}
-
-/**
- * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list.
- *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_pattern(char *data, const bool is_delete)
-{
-	return tomoyo_update_file_pattern_entry(data, is_delete);
-}
-
-static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a,
-				   const struct tomoyo_acl_head *b)
-{
-	return container_of(a, struct tomoyo_no_rewrite, head)->pattern
-		== container_of(b, struct tomoyo_no_rewrite, head)
-		->pattern;
-}
-
-/**
- * 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.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_no_rewrite_entry(const char *pattern,
-					  const bool is_delete)
-{
-	struct tomoyo_no_rewrite e = { };
-	int error;
-
-	if (!tomoyo_correct_word(pattern))
-		return -EINVAL;
-	e.pattern = tomoyo_get_name(pattern);
-	if (!e.pattern)
-		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_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
- *
- * @filename: Filename to check.
- *
- * Returns true if @filename is specified by "deny_rewrite" directive,
- * false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename)
-{
-	struct tomoyo_no_rewrite *ptr;
-	bool found = false;
-
-	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;
-		found = true;
-		break;
-	}
-	return found;
-}
-
-/**
- * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list.
- *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_no_rewrite(char *data, const bool is_delete)
-{
-	return tomoyo_update_no_rewrite_entry(data, is_delete);
+				 filename->name, buffer);
 }
 
 static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
@@ -569,6 +310,15 @@
 		tomoyo_same_name_union(&p1->name, &p2->name);
 }
 
+/**
+ * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
 static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
 				  struct tomoyo_acl_info *b,
 				  const bool is_delete)
@@ -577,19 +327,10 @@
 		->perm;
 	u16 perm = *a_perm;
 	const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
-	if (is_delete) {
+	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 {
+	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;
-	}
 	*a_perm = perm;
 	return !perm;
 }
@@ -615,8 +356,6 @@
 		.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;
 	error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
@@ -775,7 +514,6 @@
 {
 	int error;
 
- next:
 	r->type = tomoyo_p2mac[operation];
 	r->mode = tomoyo_get_mode(r->profile, r->type);
 	if (r->mode == TOMOYO_CONFIG_DISABLED)
@@ -785,10 +523,6 @@
 	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
@@ -796,16 +530,6 @@
 		 */
 	} 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_no_rewrite_file(filename)) {
-		operation = TOMOYO_TYPE_REWRITE;
-		goto next;
-	}
 	return error;
 }
 
@@ -932,43 +656,26 @@
 	struct tomoyo_request_info r;
 	int idx;
 
-	if (!path->mnt ||
-	    (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
+	if (!path->mnt)
 		return 0;
 	buf.name = NULL;
 	r.mode = TOMOYO_CONFIG_DISABLED;
 	idx = tomoyo_read_lock();
-	/*
-	 * If the filename is specified by "deny_rewrite" keyword,
-	 * 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_APPEND)
-	    && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
+	if (acc_mode &&
+	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
 	    != 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,
+		if (acc_mode & MAY_READ)
+			error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
 						       &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 && (acc_mode & MAY_WRITE))
+			error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
+						       TOMOYO_TYPE_APPEND :
+						       TOMOYO_TYPE_WRITE,
+						       &buf);
 	}
  out:
 	kfree(buf.name);
@@ -979,7 +686,7 @@
 }
 
 /**
- * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".
+ * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
  *
  * @operation: Type of operation.
  * @path:      Pointer to "struct path".
@@ -988,9 +695,10 @@
  */
 int tomoyo_path_perm(const u8 operation, struct path *path)
 {
-	int error = -ENOMEM;
-	struct tomoyo_path_info buf;
 	struct tomoyo_request_info r;
+	int error;
+	struct tomoyo_path_info buf;
+	bool is_enforce;
 	int idx;
 
 	if (!path->mnt)
@@ -998,17 +706,13 @@
 	if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
 	    == TOMOYO_CONFIG_DISABLED)
 		return 0;
+	is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
+	error = -ENOMEM;
 	buf.name = NULL;
 	idx = tomoyo_read_lock();
 	if (!tomoyo_get_realpath(&buf, path))
 		goto out;
 	switch (operation) {
-	case TOMOYO_TYPE_REWRITE:
-		if (!tomoyo_no_rewrite_file(&buf)) {
-			error = 0;
-			goto out;
-		}
-		break;
 	case TOMOYO_TYPE_RMDIR:
 	case TOMOYO_TYPE_CHROOT:
 		tomoyo_add_slash(&buf);
@@ -1018,7 +722,7 @@
  out:
 	kfree(buf.name);
 	tomoyo_read_unlock(idx);
-	if (r.mode != TOMOYO_CONFIG_ENFORCING)
+	if (!is_enforce)
 		error = 0;
 	return error;
 }
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c
index a877e4c..ba799b4 100644
--- a/security/tomoyo/gc.c
+++ b/security/tomoyo/gc.c
@@ -32,27 +32,6 @@
 	return true;
 }
 
-static void tomoyo_del_allow_read(struct list_head *element)
-{
-	struct tomoyo_readable_file *ptr =
-		container_of(element, typeof(*ptr), head.list);
-	tomoyo_put_name(ptr->filename);
-}
-
-static void tomoyo_del_file_pattern(struct list_head *element)
-{
-	struct tomoyo_no_pattern *ptr =
-		container_of(element, typeof(*ptr), head.list);
-	tomoyo_put_name(ptr->pattern);
-}
-
-static void tomoyo_del_no_rewrite(struct list_head *element)
-{
-	struct tomoyo_no_rewrite *ptr =
-		container_of(element, typeof(*ptr), head.list);
-	tomoyo_put_name(ptr->pattern);
-}
-
 static void tomoyo_del_transition_control(struct list_head *element)
 {
 	struct tomoyo_transition_control *ptr =
@@ -290,15 +269,6 @@
 		case TOMOYO_ID_AGGREGATOR:
 			tomoyo_del_aggregator(element);
 			break;
-		case TOMOYO_ID_GLOBALLY_READABLE:
-			tomoyo_del_allow_read(element);
-			break;
-		case TOMOYO_ID_PATTERN:
-			tomoyo_del_file_pattern(element);
-			break;
-		case TOMOYO_ID_NO_REWRITE:
-			tomoyo_del_no_rewrite(element);
-			break;
 		case TOMOYO_ID_MANAGER:
 			tomoyo_del_manager(element);
 			break;
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
index 162a864..f1d9e1a 100644
--- a/security/tomoyo/mount.c
+++ b/security/tomoyo/mount.c
@@ -55,9 +55,8 @@
 				flags);
 	return tomoyo_supervisor(r,
 				 TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",
-				 tomoyo_pattern(r->param.mount.dev),
-				 tomoyo_pattern(r->param.mount.dir), type,
-				 flags);
+				 r->param.mount.dev->name,
+				 r->param.mount.dir->name, type, flags);
 }
 
 static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 95d3f95..2615c7d 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -93,6 +93,12 @@
 	return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY);
 }
 
+static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+	struct path path = { mnt, dentry };
+	return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path);
+}
+
 static int tomoyo_path_truncate(struct path *path)
 {
 	return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path);
@@ -176,9 +182,10 @@
 static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
 			     unsigned long arg)
 {
-	if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
-		return tomoyo_path_perm(TOMOYO_TYPE_REWRITE, &file->f_path);
-	return 0;
+	if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)))
+		return 0;
+	return tomoyo_check_open_permission(tomoyo_domain(), &file->f_path,
+					    O_WRONLY | (arg & O_APPEND));
 }
 
 static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
@@ -258,6 +265,7 @@
 	.path_mknod          = tomoyo_path_mknod,
 	.path_link           = tomoyo_path_link,
 	.path_rename         = tomoyo_path_rename,
+	.inode_getattr       = tomoyo_inode_getattr,
 	.file_ioctl          = tomoyo_file_ioctl,
 	.path_chmod          = tomoyo_path_chmod,
 	.path_chown          = tomoyo_path_chown,
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
index 6d53932..7fb9bbf 100644
--- a/security/tomoyo/util.c
+++ b/security/tomoyo/util.c
@@ -911,44 +911,33 @@
 	if (!domain)
 		return true;
 	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+		u16 perm;
+		u8 i;
 		if (ptr->is_deleted)
 			continue;
 		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_MKDEV_ACL:
 			perm = container_of(ptr, struct tomoyo_mkdev_acl,
 					    head)->perm;
-			for (i = 0; i < TOMOYO_MAX_MKDEV_OPERATION; i++)
-				if (perm & (1 << i))
-					count++;
 			break;
 		default:
-			count++;
+			perm = 1;
 		}
+		for (i = 0; i < 16; i++)
+			if (perm & (1 << i))
+				count++;
 	}
 	if (count < tomoyo_profile(domain->profile)->learning->
 	    learning_max_entry)