TOMOYO: Use pathname specified by policy rather than execve()

Commit c9e69318 "TOMOYO: Allow wildcard for execute permission." changed execute
permission and domainname to accept wildcards. But tomoyo_find_next_domain()
was using pathname passed to execve() rather than pathname specified by the
execute permission. As a result, processes were not able to transit to domains
which contain wildcards in their domainnames.

This patch passes pathname specified by the execute permission back to
tomoyo_find_next_domain() so that processes can transit to domains which
contain wildcards in their domainnames.

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.h b/security/tomoyo/common.h
index 2ffad61..04454cb 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -246,6 +246,8 @@
 	union {
 		struct {
 			const struct tomoyo_path_info *filename;
+			/* For using wildcards at tomoyo_find_next_domain(). */
+			const struct tomoyo_path_info *matched_path;
 			u8 operation;
 		} path;
 		struct {
@@ -718,8 +720,9 @@
 /* Print out of memory warning message. */
 void tomoyo_warn_oom(const char *function);
 /* Check whether the given name matches the given name_union. */
-bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
-			       const struct tomoyo_name_union *ptr);
+const struct tomoyo_path_info *
+tomoyo_compare_name_union(const struct tomoyo_path_info *name,
+			  const struct tomoyo_name_union *ptr);
 /* Check whether the given number matches the given number_union. */
 bool tomoyo_compare_number_union(const unsigned long value,
 				 const struct tomoyo_number_union *ptr);
@@ -736,8 +739,9 @@
 bool tomoyo_parse_name_union(const char *filename,
 			     struct tomoyo_name_union *ptr);
 /* Check whether the given filename matches the given path_group. */
-bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
-			       const struct tomoyo_group *group);
+const struct tomoyo_path_info *
+tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
+			  const struct tomoyo_group *group);
 /* Check whether the given value matches the given number_group. */
 bool tomoyo_number_matches_group(const unsigned long min,
 				 const unsigned long max,
@@ -879,7 +883,7 @@
 						  const struct tomoyo_acl_head
 						  *));
 void tomoyo_check_acl(struct tomoyo_request_info *r,
-		      bool (*check_entry) (const struct tomoyo_request_info *,
+		      bool (*check_entry) (struct tomoyo_request_info *,
 					   const struct tomoyo_acl_info *));
 
 /********** External variable definitions. **********/
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index 4e0101b..3538840 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -110,7 +110,7 @@
 }
 
 void tomoyo_check_acl(struct tomoyo_request_info *r,
-		      bool (*check_entry) (const struct tomoyo_request_info *,
+		      bool (*check_entry) (struct tomoyo_request_info *,
 					   const struct tomoyo_acl_info *))
 {
 	const struct tomoyo_domain_info *domain = r->domain;
@@ -465,6 +465,19 @@
 		goto retry;
 	if (retval < 0)
 		goto out;
+	/*
+	 * To be able to specify domainnames with wildcards, use the
+	 * pathname specified in the policy (which may contain
+	 * wildcard) rather than the pathname passed to execve()
+	 * (which never contains wildcard).
+	 */
+	if (r.param.path.matched_path) {
+		if (need_kfree)
+			kfree(rn.name);
+		need_kfree = false;
+		/* This is OK because it is read only. */
+		rn = *r.param.path.matched_path;
+	}
 
 	/* Calculate domain to transit to. */
 	switch (tomoyo_transition_type(old_domain->domainname, &rn)) {
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index f7877fa..9d32f18 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -95,12 +95,15 @@
 		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);
-	return tomoyo_path_matches_pattern(name, ptr->filename);
+	if (tomoyo_path_matches_pattern(name, ptr->filename))
+		return ptr->filename;
+	return NULL;
 }
 
 void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
@@ -504,16 +507,21 @@
 	return tomoyo_update_no_rewrite_entry(data, is_delete);
 }
 
-static bool tomoyo_check_path_acl(const struct tomoyo_request_info *r,
+static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
 				  const struct tomoyo_acl_info *ptr)
 {
 	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
 							 head);
-	return (acl->perm & (1 << r->param.path.operation)) &&
-		tomoyo_compare_name_union(r->param.path.filename, &acl->name);
+	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 false;
 }
 
-static bool tomoyo_check_path_number_acl(const struct tomoyo_request_info *r,
+static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
 					 const struct tomoyo_acl_info *ptr)
 {
 	const struct tomoyo_path_number_acl *acl =
@@ -525,7 +533,7 @@
 					  &acl->name);
 }
 
-static bool tomoyo_check_path2_acl(const struct tomoyo_request_info *r,
+static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
 				   const struct tomoyo_acl_info *ptr)
 {
 	const struct tomoyo_path2_acl *acl =
@@ -536,7 +544,7 @@
 					     &acl->name2);
 }
 
-static bool tomoyo_check_mkdev_acl(const struct tomoyo_request_info *r,
+static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
 				const struct tomoyo_acl_info *ptr)
 {
 	const struct tomoyo_mkdev_acl *acl =
diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c
index 3f0a2ab..e94352c 100644
--- a/security/tomoyo/group.c
+++ b/security/tomoyo/group.c
@@ -80,24 +80,24 @@
  * @pathname:        The name of pathname.
  * @group:           Pointer to "struct tomoyo_path_group".
  *
- * Returns true if @pathname matches pathnames in @group, false otherwise.
+ * Returns matched member's pathname if @pathname matches pathnames in @group,
+ * NULL otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
-			       const struct tomoyo_group *group)
+const struct tomoyo_path_info *
+tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
+			  const struct tomoyo_group *group)
 {
 	struct tomoyo_path_group *member;
-	bool matched = false;
 	list_for_each_entry_rcu(member, &group->member_list, head.list) {
 		if (member->head.is_deleted)
 			continue;
 		if (!tomoyo_path_matches_pattern(pathname, member->member_name))
 			continue;
-		matched = true;
-		break;
+		return member->member_name;
 	}
-	return matched;
+	return NULL;
 }
 
 /**
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
index cfeff87..82bf8c2 100644
--- a/security/tomoyo/mount.c
+++ b/security/tomoyo/mount.c
@@ -60,7 +60,7 @@
 				 flags);
 }
 
-static bool tomoyo_check_mount_acl(const struct tomoyo_request_info *r,
+static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
 				   const struct tomoyo_acl_info *ptr)
 {
 	const struct tomoyo_mount_acl *acl =