diff mbox series

[8/8] libsepol/cil: add support for prefix/suffix filename transtions to CIL

Message ID 20230531114914.2237609-9-juraj@jurajmarcin.com (mailing list archive)
State Superseded
Delegated to: Petr Lautrbach
Headers show
Series checkpolicy, libsepol: add prefix/suffix matching to filename type transitions | expand

Commit Message

Juraj Marcin May 31, 2023, 11:49 a.m. UTC
This patch implements the support for prefix/suffix filename transitions
in CIL structures as well as to CIL policy parser.

Reviewed-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Juraj Marcin <juraj@jurajmarcin.com>
---
 libsepol/cil/src/cil.c             |  8 ++++++++
 libsepol/cil/src/cil_binary.c      |  8 ++++----
 libsepol/cil/src/cil_build_ast.c   | 25 +++++++++++++++++++------
 libsepol/cil/src/cil_copy_ast.c    |  1 +
 libsepol/cil/src/cil_internal.h    |  5 +++++
 libsepol/cil/src/cil_policy.c      | 17 ++++++++++++++++-
 libsepol/cil/src/cil_resolve_ast.c | 10 ++++++++++
 libsepol/cil/src/cil_write_ast.c   |  2 ++
 8 files changed, 65 insertions(+), 11 deletions(-)

Comments

James Carter June 1, 2023, 9 p.m. UTC | #1
On Wed, May 31, 2023 at 7:51 AM Juraj Marcin <juraj@jurajmarcin.com> wrote:
>
> This patch implements the support for prefix/suffix filename transitions
> in CIL structures as well as to CIL policy parser.
>

As for the checkpolicy patch, I would like to see some examples of the
new syntax here.

> Reviewed-by: Ondrej Mosnacek <omosnace@redhat.com>
> Signed-off-by: Juraj Marcin <juraj@jurajmarcin.com>
> ---
>  libsepol/cil/src/cil.c             |  8 ++++++++
>  libsepol/cil/src/cil_binary.c      |  8 ++++----
>  libsepol/cil/src/cil_build_ast.c   | 25 +++++++++++++++++++------
>  libsepol/cil/src/cil_copy_ast.c    |  1 +
>  libsepol/cil/src/cil_internal.h    |  5 +++++
>  libsepol/cil/src/cil_policy.c      | 17 ++++++++++++++++-
>  libsepol/cil/src/cil_resolve_ast.c | 10 ++++++++++
>  libsepol/cil/src/cil_write_ast.c   |  2 ++
>  8 files changed, 65 insertions(+), 11 deletions(-)
>
> diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
> index 38edcf8e..3b086de9 100644
> --- a/libsepol/cil/src/cil.c
> +++ b/libsepol/cil/src/cil.c
> @@ -95,6 +95,9 @@ char *CIL_KEY_TUNABLEIF;
>  char *CIL_KEY_ALLOW;
>  char *CIL_KEY_DONTAUDIT;
>  char *CIL_KEY_TYPETRANSITION;
> +char *CIL_KEY_MATCH_EXACT;
> +char *CIL_KEY_MATCH_PREFIX;
> +char *CIL_KEY_MATCH_SUFFIX;
>  char *CIL_KEY_TYPECHANGE;
>  char *CIL_KEY_CALL;
>  char *CIL_KEY_TUNABLE;
> @@ -264,6 +267,9 @@ static void cil_init_keys(void)
>         CIL_KEY_ALLOW = cil_strpool_add("allow");
>         CIL_KEY_DONTAUDIT = cil_strpool_add("dontaudit");
>         CIL_KEY_TYPETRANSITION = cil_strpool_add("typetransition");
> +       CIL_KEY_MATCH_EXACT = cil_strpool_add("match_exact");
> +       CIL_KEY_MATCH_PREFIX = cil_strpool_add("match_prefix");
> +       CIL_KEY_MATCH_SUFFIX = cil_strpool_add("match_suffix");

Also, like the checkpolicy patch, I would prefer "exact", "prefix",
and "suffix" unless using those keywords will cause problems.

Thanks,
Jim


>         CIL_KEY_TYPECHANGE = cil_strpool_add("typechange");
>         CIL_KEY_CALL = cil_strpool_add("call");
>         CIL_KEY_TUNABLE = cil_strpool_add("tunable");
> @@ -2387,6 +2393,8 @@ void cil_nametypetransition_init(struct cil_nametypetransition **nametypetrans)
>         (*nametypetrans)->obj = NULL;
>         (*nametypetrans)->name_str = NULL;
>         (*nametypetrans)->name = NULL;
> +       (*nametypetrans)->name_match_str = NULL;
> +       (*nametypetrans)->name_match = NAME_TRANS_MATCH_EXACT;
>         (*nametypetrans)->result_str = NULL;
>         (*nametypetrans)->result = NULL;
>  }
> diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
> index ffa44be7..ea0cef32 100644
> --- a/libsepol/cil/src/cil_binary.c
> +++ b/libsepol/cil/src/cil_binary.c
> @@ -1193,7 +1193,7 @@ static int __cil_typetransition_to_avtab_helper(policydb_t *pdb,
>                                                 type_datum_t *sepol_src,
>                                                 type_datum_t *sepol_tgt,
>                                                 struct cil_list *class_list,
> -                                               char *name,
> +                                               char *name, uint8_t name_match,
>                                                 type_datum_t *sepol_result)
>  {
>         int rc;
> @@ -1211,7 +1211,7 @@ static int __cil_typetransition_to_avtab_helper(policydb_t *pdb,
>                 avt_key.target_type = sepol_tgt->s.value;
>                 avt_key.target_class = sepol_obj->s.value;
>                 rc = avtab_insert_filename_trans(&pdb->te_avtab, &avt_key,
> -                       sepol_result->s.value, name, NAME_TRANS_MATCH_EXACT,
> +                       sepol_result->s.value, name, name_match,
>                         &otype);
>                 if (rc != SEPOL_OK) {
>                         if (rc == SEPOL_EEXIST) {
> @@ -1280,7 +1280,7 @@ static int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *d
>
>                         rc = __cil_typetransition_to_avtab_helper(
>                                 pdb, sepol_src, sepol_src, class_list,
> -                               name, sepol_result
> +                               name, typetrans->name_match, sepol_result
>                         );
>                         if (rc != SEPOL_OK) goto exit;
>                 }
> @@ -1298,7 +1298,7 @@ static int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *d
>
>                                 rc = __cil_typetransition_to_avtab_helper(
>                                         pdb, sepol_src, sepol_tgt, class_list,
> -                                       name, sepol_result
> +                                       name, typetrans->name_match, sepol_result
>                                 );
>                                 if (rc != SEPOL_OK) goto exit;
>                         }
> diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
> index 4177c9f6..47513f92 100644
> --- a/libsepol/cil/src/cil_build_ast.c
> +++ b/libsepol/cil/src/cil_build_ast.c
> @@ -3334,10 +3334,11 @@ int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren
>                 CIL_SYN_STRING,
>                 CIL_SYN_STRING,
>                 CIL_SYN_STRING | CIL_SYN_END,
> -               CIL_SYN_END
> +               CIL_SYN_STRING | CIL_SYN_END,
> +               CIL_SYN_END,
>         };
>         size_t syntax_len = sizeof(syntax)/sizeof(*syntax);
> -       char *s1, *s2, *s3, *s4, *s5;
> +       char *s1, *s2, *s3, *s4, *s5, *s6;
>
>         if (db == NULL || parse_current == NULL || ast_node == NULL ) {
>                 goto exit;
> @@ -3353,16 +3354,27 @@ int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren
>         s3 = parse_current->next->next->next->data;
>         s4 = parse_current->next->next->next->next->data;
>         s5 = NULL;
> +       s6 = NULL;
>
>         if (parse_current->next->next->next->next->next) {
>                 if (s4 == CIL_KEY_STAR) {
> -                       s4 = parse_current->next->next->next->next->next->data;
> +                       if (parse_current->next->next->next->next->next->next) {
> +                               s4 = parse_current->next->next->next->next->next->next->data;
> +                       } else {
> +                               s4 = parse_current->next->next->next->next->next->data;
> +                       }
>                 } else {
> -                       s5 = parse_current->next->next->next->next->next->data;
> +                       if (parse_current->next->next->next->next->next->next) {
> +                               s5 = parse_current->next->next->next->next->next->data;
> +                               s6 = parse_current->next->next->next->next->next->next->data;
> +                       } else {
> +                               s5 = CIL_KEY_MATCH_EXACT;
> +                               s6 = parse_current->next->next->next->next->next->data;
> +                       }
>                 }
>         }
>
> -       if (s5) {
> +       if (s6) {
>                 struct cil_nametypetransition *nametypetrans = NULL;
>
>                 cil_nametypetransition_init(&nametypetrans);
> @@ -3370,8 +3382,9 @@ int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren
>                 nametypetrans->src_str = s1;
>                 nametypetrans->tgt_str = s2;
>                 nametypetrans->obj_str = s3;
> -               nametypetrans->result_str = s5;
> +               nametypetrans->result_str = s6;
>                 nametypetrans->name_str = s4;
> +               nametypetrans->name_match_str = s5;
>
>                 ast_node->data = nametypetrans;
>                 ast_node->flavor = CIL_NAMETYPETRANSITION;
> diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c
> index 17f05021..a2d2fe40 100644
> --- a/libsepol/cil/src/cil_copy_ast.c
> +++ b/libsepol/cil/src/cil_copy_ast.c
> @@ -726,6 +726,7 @@ int cil_copy_nametypetransition(__attribute__((unused)) struct cil_db *db, void
>         new->tgt_str = orig->tgt_str;
>         new->obj_str = orig->obj_str;
>         new->name_str = orig->name_str;
> +       new->name_match_str = orig->name_match_str;
>         new->result_str = orig->result_str;
>
>
> diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
> index a7604762..f7a8d0f7 100644
> --- a/libsepol/cil/src/cil_internal.h
> +++ b/libsepol/cil/src/cil_internal.h
> @@ -112,6 +112,9 @@ extern char *CIL_KEY_TUNABLEIF;
>  extern char *CIL_KEY_ALLOW;
>  extern char *CIL_KEY_DONTAUDIT;
>  extern char *CIL_KEY_TYPETRANSITION;
> +extern char *CIL_KEY_MATCH_EXACT;
> +extern char *CIL_KEY_MATCH_PREFIX;
> +extern char *CIL_KEY_MATCH_SUFFIX;
>  extern char *CIL_KEY_TYPECHANGE;
>  extern char *CIL_KEY_CALL;
>  extern char *CIL_KEY_TUNABLE;
> @@ -575,6 +578,8 @@ struct cil_nametypetransition {
>         struct cil_class *obj;
>         char *name_str;
>         struct cil_name *name;
> +       char *name_match_str;
> +       uint8_t name_match;
>         char *result_str;
>         void *result; /* type or alias */
>
> diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c
> index feb97868..c8253818 100644
> --- a/libsepol/cil/src/cil_policy.c
> +++ b/libsepol/cil/src/cil_policy.c
> @@ -1260,6 +1260,7 @@ static void cil_nametypetransition_to_policy(FILE *out, struct cil_nametypetrans
>         struct cil_name *name;
>         struct cil_list *class_list;
>         struct cil_list_item *i1;
> +       const char *name_match_str = "";
>
>         src = trans->src;
>         tgt = trans->tgt;
> @@ -1268,7 +1269,21 @@ static void cil_nametypetransition_to_policy(FILE *out, struct cil_nametypetrans
>
>         class_list = cil_expand_class(trans->obj);
>         cil_list_for_each(i1, class_list) {
> -               fprintf(out, "type_transition %s %s : %s %s \"%s\";\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn, name->datum.fqn);
> +               switch (trans->name_match) {
> +               case NAME_TRANS_MATCH_EXACT:
> +                       name_match_str = "";
> +                       break;
> +               case NAME_TRANS_MATCH_PREFIX:
> +                       name_match_str = " MATCH_PREFIX";
> +                       break;
> +               case NAME_TRANS_MATCH_SUFFIX:
> +                       name_match_str = " MATCH_SUFFIX";
> +                       break;
> +               default:
> +                       name_match_str = "???";
> +                       break;
> +               }
> +               fprintf(out, "type_transition %s %s : %s %s \"%s\"%s;\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn, name->datum.fqn, name_match_str);
>         }
>         cil_list_destroy(&class_list, CIL_FALSE);
>  }
> diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
> index d2bfdc81..fbb0fdcc 100644
> --- a/libsepol/cil/src/cil_resolve_ast.c
> +++ b/libsepol/cil/src/cil_resolve_ast.c
> @@ -668,6 +668,16 @@ int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_ar
>                 nametypetrans->name = (struct cil_name *)name_datum;
>         }
>
> +       if (nametypetrans->name_match_str == CIL_KEY_MATCH_EXACT) {
> +               nametypetrans->name_match = NAME_TRANS_MATCH_EXACT;
> +       } else if (nametypetrans->name_match_str == CIL_KEY_MATCH_PREFIX) {
> +               nametypetrans->name_match = NAME_TRANS_MATCH_PREFIX;
> +       } else if (nametypetrans->name_match_str == CIL_KEY_MATCH_SUFFIX) {
> +               nametypetrans->name_match = NAME_TRANS_MATCH_SUFFIX;
> +       } else {
> +               cil_tree_log(current, CIL_ERR, "Invalid name match type \"%s\"", nametypetrans->name_match_str);
> +       }
> +
>         rc = cil_resolve_name(current, nametypetrans->result_str, CIL_SYM_TYPES, extra_args, &result_datum);
>         if (rc != SEPOL_OK) {
>                 goto exit;
> diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c
> index b75784ef..d96f6c39 100644
> --- a/libsepol/cil/src/cil_write_ast.c
> +++ b/libsepol/cil/src/cil_write_ast.c
> @@ -1168,6 +1168,8 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node)
>                 fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
>                 fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str));
>                 fprintf(out, "\"%s\" ", datum_or_str(DATUM(rule->name), rule->name_str));
> +               if (rule->name_match != NAME_TRANS_MATCH_EXACT)
> +                       fprintf(out, "%s ", rule->name_match_str);
>                 fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str));
>                 fprintf(out, ")\n");
>                 break;
> --
> 2.40.0
>
diff mbox series

Patch

diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
index 38edcf8e..3b086de9 100644
--- a/libsepol/cil/src/cil.c
+++ b/libsepol/cil/src/cil.c
@@ -95,6 +95,9 @@  char *CIL_KEY_TUNABLEIF;
 char *CIL_KEY_ALLOW;
 char *CIL_KEY_DONTAUDIT;
 char *CIL_KEY_TYPETRANSITION;
+char *CIL_KEY_MATCH_EXACT;
+char *CIL_KEY_MATCH_PREFIX;
+char *CIL_KEY_MATCH_SUFFIX;
 char *CIL_KEY_TYPECHANGE;
 char *CIL_KEY_CALL;
 char *CIL_KEY_TUNABLE;
@@ -264,6 +267,9 @@  static void cil_init_keys(void)
 	CIL_KEY_ALLOW = cil_strpool_add("allow");
 	CIL_KEY_DONTAUDIT = cil_strpool_add("dontaudit");
 	CIL_KEY_TYPETRANSITION = cil_strpool_add("typetransition");
+	CIL_KEY_MATCH_EXACT = cil_strpool_add("match_exact");
+	CIL_KEY_MATCH_PREFIX = cil_strpool_add("match_prefix");
+	CIL_KEY_MATCH_SUFFIX = cil_strpool_add("match_suffix");
 	CIL_KEY_TYPECHANGE = cil_strpool_add("typechange");
 	CIL_KEY_CALL = cil_strpool_add("call");
 	CIL_KEY_TUNABLE = cil_strpool_add("tunable");
@@ -2387,6 +2393,8 @@  void cil_nametypetransition_init(struct cil_nametypetransition **nametypetrans)
 	(*nametypetrans)->obj = NULL;
 	(*nametypetrans)->name_str = NULL;
 	(*nametypetrans)->name = NULL;
+	(*nametypetrans)->name_match_str = NULL;
+	(*nametypetrans)->name_match = NAME_TRANS_MATCH_EXACT;
 	(*nametypetrans)->result_str = NULL;
 	(*nametypetrans)->result = NULL;
 }
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
index ffa44be7..ea0cef32 100644
--- a/libsepol/cil/src/cil_binary.c
+++ b/libsepol/cil/src/cil_binary.c
@@ -1193,7 +1193,7 @@  static int __cil_typetransition_to_avtab_helper(policydb_t *pdb,
 						type_datum_t *sepol_src,
 						type_datum_t *sepol_tgt,
 						struct cil_list *class_list,
-						char *name,
+						char *name, uint8_t name_match,
 						type_datum_t *sepol_result)
 {
 	int rc;
@@ -1211,7 +1211,7 @@  static int __cil_typetransition_to_avtab_helper(policydb_t *pdb,
 		avt_key.target_type = sepol_tgt->s.value;
 		avt_key.target_class = sepol_obj->s.value;
 		rc = avtab_insert_filename_trans(&pdb->te_avtab, &avt_key,
-			sepol_result->s.value, name, NAME_TRANS_MATCH_EXACT,
+			sepol_result->s.value, name, name_match,
 			&otype);
 		if (rc != SEPOL_OK) {
 			if (rc == SEPOL_EEXIST) {
@@ -1280,7 +1280,7 @@  static int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *d
 
 			rc = __cil_typetransition_to_avtab_helper(
 				pdb, sepol_src, sepol_src, class_list,
-				name, sepol_result
+				name, typetrans->name_match, sepol_result
 			);
 			if (rc != SEPOL_OK) goto exit;
 		}
@@ -1298,7 +1298,7 @@  static int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *d
 
 				rc = __cil_typetransition_to_avtab_helper(
 					pdb, sepol_src, sepol_tgt, class_list,
-					name, sepol_result
+					name, typetrans->name_match, sepol_result
 				);
 				if (rc != SEPOL_OK) goto exit;
 			}
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
index 4177c9f6..47513f92 100644
--- a/libsepol/cil/src/cil_build_ast.c
+++ b/libsepol/cil/src/cil_build_ast.c
@@ -3334,10 +3334,11 @@  int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren
 		CIL_SYN_STRING,
 		CIL_SYN_STRING,
 		CIL_SYN_STRING | CIL_SYN_END,
-		CIL_SYN_END
+		CIL_SYN_STRING | CIL_SYN_END,
+		CIL_SYN_END,
 	};
 	size_t syntax_len = sizeof(syntax)/sizeof(*syntax);
-	char *s1, *s2, *s3, *s4, *s5;
+	char *s1, *s2, *s3, *s4, *s5, *s6;
 
 	if (db == NULL || parse_current == NULL || ast_node == NULL ) {
 		goto exit;
@@ -3353,16 +3354,27 @@  int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren
 	s3 = parse_current->next->next->next->data;
 	s4 = parse_current->next->next->next->next->data;
 	s5 = NULL;
+	s6 = NULL;
 
 	if (parse_current->next->next->next->next->next) {
 		if (s4 == CIL_KEY_STAR) {
-			s4 = parse_current->next->next->next->next->next->data;
+			if (parse_current->next->next->next->next->next->next) {
+				s4 = parse_current->next->next->next->next->next->next->data;
+			} else {
+				s4 = parse_current->next->next->next->next->next->data;
+			}
 		} else {
-			s5 = parse_current->next->next->next->next->next->data;
+			if (parse_current->next->next->next->next->next->next) {
+				s5 = parse_current->next->next->next->next->next->data;
+				s6 = parse_current->next->next->next->next->next->next->data;
+			} else {
+				s5 = CIL_KEY_MATCH_EXACT;
+				s6 = parse_current->next->next->next->next->next->data;
+			}
 		}
 	}
 
-	if (s5) {
+	if (s6) {
 		struct cil_nametypetransition *nametypetrans = NULL;
 
 		cil_nametypetransition_init(&nametypetrans);
@@ -3370,8 +3382,9 @@  int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren
 		nametypetrans->src_str = s1;
 		nametypetrans->tgt_str = s2;
 		nametypetrans->obj_str = s3;
-		nametypetrans->result_str = s5;
+		nametypetrans->result_str = s6;
 		nametypetrans->name_str = s4;
+		nametypetrans->name_match_str = s5;
 
 		ast_node->data = nametypetrans;
 		ast_node->flavor = CIL_NAMETYPETRANSITION;
diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c
index 17f05021..a2d2fe40 100644
--- a/libsepol/cil/src/cil_copy_ast.c
+++ b/libsepol/cil/src/cil_copy_ast.c
@@ -726,6 +726,7 @@  int cil_copy_nametypetransition(__attribute__((unused)) struct cil_db *db, void
 	new->tgt_str = orig->tgt_str;
 	new->obj_str = orig->obj_str;
 	new->name_str = orig->name_str;
+	new->name_match_str = orig->name_match_str;
 	new->result_str = orig->result_str;
 
 
diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
index a7604762..f7a8d0f7 100644
--- a/libsepol/cil/src/cil_internal.h
+++ b/libsepol/cil/src/cil_internal.h
@@ -112,6 +112,9 @@  extern char *CIL_KEY_TUNABLEIF;
 extern char *CIL_KEY_ALLOW;
 extern char *CIL_KEY_DONTAUDIT;
 extern char *CIL_KEY_TYPETRANSITION;
+extern char *CIL_KEY_MATCH_EXACT;
+extern char *CIL_KEY_MATCH_PREFIX;
+extern char *CIL_KEY_MATCH_SUFFIX;
 extern char *CIL_KEY_TYPECHANGE;
 extern char *CIL_KEY_CALL;
 extern char *CIL_KEY_TUNABLE;
@@ -575,6 +578,8 @@  struct cil_nametypetransition {
 	struct cil_class *obj;
 	char *name_str;
 	struct cil_name *name;
+	char *name_match_str;
+	uint8_t name_match;
 	char *result_str;
 	void *result; /* type or alias */
 
diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c
index feb97868..c8253818 100644
--- a/libsepol/cil/src/cil_policy.c
+++ b/libsepol/cil/src/cil_policy.c
@@ -1260,6 +1260,7 @@  static void cil_nametypetransition_to_policy(FILE *out, struct cil_nametypetrans
 	struct cil_name *name;
 	struct cil_list *class_list;
 	struct cil_list_item *i1;
+	const char *name_match_str = "";
 
 	src = trans->src;
 	tgt = trans->tgt;
@@ -1268,7 +1269,21 @@  static void cil_nametypetransition_to_policy(FILE *out, struct cil_nametypetrans
 
 	class_list = cil_expand_class(trans->obj);
 	cil_list_for_each(i1, class_list) {
-		fprintf(out, "type_transition %s %s : %s %s \"%s\";\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn, name->datum.fqn);
+		switch (trans->name_match) {
+		case NAME_TRANS_MATCH_EXACT:
+			name_match_str = "";
+			break;
+		case NAME_TRANS_MATCH_PREFIX:
+			name_match_str = " MATCH_PREFIX";
+			break;
+		case NAME_TRANS_MATCH_SUFFIX:
+			name_match_str = " MATCH_SUFFIX";
+			break;
+		default:
+			name_match_str = "???";
+			break;
+		}
+		fprintf(out, "type_transition %s %s : %s %s \"%s\"%s;\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn, name->datum.fqn, name_match_str);
 	}
 	cil_list_destroy(&class_list, CIL_FALSE);
 }
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
index d2bfdc81..fbb0fdcc 100644
--- a/libsepol/cil/src/cil_resolve_ast.c
+++ b/libsepol/cil/src/cil_resolve_ast.c
@@ -668,6 +668,16 @@  int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_ar
 		nametypetrans->name = (struct cil_name *)name_datum;
 	}
 
+	if (nametypetrans->name_match_str == CIL_KEY_MATCH_EXACT) {
+		nametypetrans->name_match = NAME_TRANS_MATCH_EXACT;
+	} else if (nametypetrans->name_match_str == CIL_KEY_MATCH_PREFIX) {
+		nametypetrans->name_match = NAME_TRANS_MATCH_PREFIX;
+	} else if (nametypetrans->name_match_str == CIL_KEY_MATCH_SUFFIX) {
+		nametypetrans->name_match = NAME_TRANS_MATCH_SUFFIX;
+	} else {
+		cil_tree_log(current, CIL_ERR, "Invalid name match type \"%s\"", nametypetrans->name_match_str);
+	}
+
 	rc = cil_resolve_name(current, nametypetrans->result_str, CIL_SYM_TYPES, extra_args, &result_datum);
 	if (rc != SEPOL_OK) {
 		goto exit;
diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c
index b75784ef..d96f6c39 100644
--- a/libsepol/cil/src/cil_write_ast.c
+++ b/libsepol/cil/src/cil_write_ast.c
@@ -1168,6 +1168,8 @@  void cil_write_ast_node(FILE *out, struct cil_tree_node *node)
 		fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
 		fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str));
 		fprintf(out, "\"%s\" ", datum_or_str(DATUM(rule->name), rule->name_str));
+		if (rule->name_match != NAME_TRANS_MATCH_EXACT)
+			fprintf(out, "%s ", rule->name_match_str);
 		fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str));
 		fprintf(out, ")\n");
 		break;