Re: [PATCH v3] checkpolicy,libsepol: add prefix/suffix matching to filename type transitions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 8 Nov 2023 at 16:52, James Carter <jwcart2@xxxxxxxxx> wrote:
>
> On Wed, Nov 8, 2023 at 5:35 AM Juraj Marcin <juraj@xxxxxxxxxxxxxxx> wrote:
> >
> > Currently, filename transitions are stored separately from other type
> > enforcement rules and only support exact name matching. However, in
> > practice, the names contain variable parts. This leads to many
> > duplicated rules in the policy that differ only in the part of the name,
> > or it is even impossible to cover all possible combinations.
> >
> > This patch implements the equivalent changes made by this kernel
> > patch [1].
> >
> > This patch updates the policydb structure to contain prefix and suffix
> > filename transition tables along normal filename transitions table and
> > updates the code that accesses those tables. Furthermore, it adds
> > match_type attribute to module and CIL structures that store filename
> > transitions and updates functions that parse conf and CIL policy files.
> >
> > This patch does not significantly change the binary policy size when
> > prefix/suffix rules are not used. In addition, with prefix/suffix rules,
> > the number of filename transitions can be reduced, and therefore also
> > binary policy size can be reduced.
> >
> > Syntax of the new prefix/suffix filename transition rule:
> >
> >     type_transition source_type target_type : class default_type object_name match_type;
> >
> >     (typetransition source_type_id target_type_id class_id object_name match_type default_type_id)
> >
> > where match_type is either keyword "prefix" or "suffix"
> >
> > Examples:
> >
> >     type_transition ta tb:CLASS01 tc "file01" prefix;
> >     type_transition td te:CLASS01 tf "file02" suffix;
> >
> >     (typetransition ta tb CLASS01 "file01" prefix td)
> >     (typetransition td te CLASS01 "file02" suffix tf)
> >
> > In the kernel, the rules have the following order of priority, if no
> > matching rule is found, the code moves on to the next category:
> > - exact filename transitions,
> > - prefix filename transitions in the order of the longest prefix match,
> > - suffix filename transitions in the order of the longest suffix match.
> > This ensures the compatibility with older policies.
> >
> > [1]: https://lore.kernel.org/selinux/20231108101427.3514509-1-juraj@xxxxxxxxxxxxxxx/
> >
> > Reviewed-by: Ondrej Mosnacek <omosnace@xxxxxxxxxx>
> > Signed-off-by: Juraj Marcin <juraj@xxxxxxxxxxxxxxx>
> > ---
> > v3:
> > - reworked the solution from scratch, this time only adding the
> >   prefix/suffix matching feature without moving filename transition
> >   rules to the avtab
> > ---
> >  checkpolicy/policy_define.c                |  7 +-
> >  checkpolicy/policy_define.h                |  2 +-
> >  checkpolicy/policy_parse.y                 | 13 +++-
> >  checkpolicy/policy_scan.l                  |  4 ++
> >  checkpolicy/test/dismod.c                  | 14 +++-
> >  checkpolicy/test/dispol.c                  | 26 ++++++-
> >  libsepol/cil/src/cil.c                     |  6 ++
> >  libsepol/cil/src/cil_binary.c              |  8 +--
> >  libsepol/cil/src/cil_build_ast.c           | 26 +++++--
> >  libsepol/cil/src/cil_copy_ast.c            |  1 +
> >  libsepol/cil/src/cil_internal.h            |  4 ++
> >  libsepol/cil/src/cil_policy.c              | 17 ++++-
> >  libsepol/cil/src/cil_resolve_ast.c         | 12 ++++
> >  libsepol/cil/src/cil_write_ast.c           |  2 +
> >  libsepol/include/sepol/policydb/policydb.h | 20 ++++--
> >  libsepol/src/expand.c                      | 17 ++++-
> >  libsepol/src/kernel_to_cil.c               | 36 +++++++++-
> >  libsepol/src/kernel_to_conf.c              | 36 +++++++++-
> >  libsepol/src/link.c                        |  1 +
> >  libsepol/src/module_to_cil.c               | 21 ++++--
> >  libsepol/src/policydb.c                    | 82 +++++++++++++++++-----
> >  libsepol/src/policydb_validate.c           | 36 ++++++++--
> >  libsepol/src/write.c                       | 44 +++++++++---

Maybe add some syntax tests to secilc/test/ and
checkpolicy/tests/policy_allonce(_mls).conf.

> >  23 files changed, 367 insertions(+), 68 deletions(-)
> >
> > diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
> > index 260e609d..fb8325ee 100644
> > --- a/checkpolicy/policy_define.c
> > +++ b/checkpolicy/policy_define.c
> > @@ -3159,7 +3159,7 @@ avrule_t *define_cond_filename_trans(void)
> >         return COND_ERR;
> >  }
> >
> > -int define_filename_trans(void)
> > +int define_filename_trans(uint32_t match_type)
> >  {
> >         char *id, *name = NULL;
> >         type_set_t stypes, ttypes;
> > @@ -3261,7 +3261,7 @@ int define_filename_trans(void)
> >                         ebitmap_for_each_positive_bit(&e_ttypes, tnode, t) {
> >                                 rc = policydb_filetrans_insert(
> >                                         policydbp, s+1, t+1, c+1, name,
> > -                                       NULL, otype, NULL
> > +                                       NULL, otype, match_type, NULL
> >                                 );
> >                                 if (rc != SEPOL_OK) {
> >                                         if (rc == SEPOL_EEXIST) {
> > @@ -3279,7 +3279,7 @@ int define_filename_trans(void)
> >                         if (self) {
> >                                 rc = policydb_filetrans_insert(
> >                                         policydbp, s+1, s+1, c+1, name,
> > -                                       NULL, otype, NULL
> > +                                       NULL, otype, match_type, NULL
> >                                 );
> >                                 if (rc != SEPOL_OK) {
> >                                         if (rc == SEPOL_EEXIST) {
> > @@ -3317,6 +3317,7 @@ int define_filename_trans(void)
> >                 ftr->tclass = c + 1;
> >                 ftr->otype = otype;
> >                 ftr->flags = self ? RULE_SELF : 0;
> > +               ftr->match_type = match_type;
> >         }
> >
> >         free(name);
> > diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
> > index 075b048d..05869346 100644
> > --- a/checkpolicy/policy_define.h
> > +++ b/checkpolicy/policy_define.h
> > @@ -57,7 +57,7 @@ int define_role_trans(int class_specified);
> >  int define_role_types(void);
> >  int define_role_attr(void);
> >  int define_roleattribute(void);
> > -int define_filename_trans(void);
> > +int define_filename_trans(uint32_t match_type);
> >  int define_sens(void);
> >  int define_te_avtab(int which);
> >  int define_te_avtab_extended_perms(int which);
> > diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
> > index 356626e2..ee4be4ea 100644
> > --- a/checkpolicy/policy_parse.y
> > +++ b/checkpolicy/policy_parse.y
> > @@ -153,6 +153,7 @@ typedef int (* require_func_t)(int pass);
> >  %token FILESYSTEM
> >  %token DEFAULT_USER DEFAULT_ROLE DEFAULT_TYPE DEFAULT_RANGE
> >  %token LOW_HIGH LOW HIGH GLBLUB
> > +%token PREFIX SUFFIX
> >
> >  %left OR
> >  %left XOR
> > @@ -410,6 +411,12 @@ cond_rule_def           : cond_transition_def
> >                         { $$ = NULL; }
> >                          ;
> >  cond_transition_def    : TYPE_TRANSITION names names ':' names identifier filename ';'
> > +                        { $$ = define_cond_filename_trans() ;
> > +                          if ($$ == COND_ERR) return -1;}
> > +                       | TYPE_TRANSITION names names ':' names identifier filename PREFIX ';'
> > +                        { $$ = define_cond_filename_trans() ;
> > +                          if ($$ == COND_ERR) return -1;}
> > +                       | TYPE_TRANSITION names names ':' names identifier filename SUFFIX ';'
> >                          { $$ = define_cond_filename_trans() ;
> >                            if ($$ == COND_ERR) return -1;}
> >                         | TYPE_TRANSITION names names ':' names identifier ';'
> > @@ -449,7 +456,11 @@ cond_dontaudit_def : DONTAUDIT names names ':' names names ';'
> >                         ;
> >                         ;
> >  transition_def         : TYPE_TRANSITION  names names ':' names identifier filename ';'
> > -                       {if (define_filename_trans()) return -1; }
> > +                       {if (define_filename_trans(FILENAME_TRANS_MATCH_EXACT)) return -1; }
> > +                       | TYPE_TRANSITION  names names ':' names identifier filename PREFIX ';'
> > +                       {if (define_filename_trans(FILENAME_TRANS_MATCH_PREFIX)) return -1; }
> > +                       | TYPE_TRANSITION  names names ':' names identifier filename SUFFIX ';'
> > +                       {if (define_filename_trans(FILENAME_TRANS_MATCH_SUFFIX)) return -1; }
> >                         | TYPE_TRANSITION names names ':' names identifier ';'
> >                          {if (define_compute_type(AVRULE_TRANSITION)) return -1;}
> >                          | TYPE_MEMBER names names ':' names identifier ';'
> > diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
> > index c998ff8b..0780ef15 100644
> > --- a/checkpolicy/policy_scan.l
> > +++ b/checkpolicy/policy_scan.l
> > @@ -270,6 +270,10 @@ low |
> >  LOW                            { return(LOW); }
> >  glblub |
> >  GLBLUB                         { return(GLBLUB); }
> > +PREFIX |
> > +prefix                         { return(PREFIX); }
> > +SUFFIX |
> > +suffix                         { return(SUFFIX); }
> >  "/"[^ \n\r\t\f]*               { return(PATH); }
> >  \""/"[^\"\n]*\"                { return(QPATH); }
> >  \"[^"/"\"\n]+\"        { return(FILENAME); }
> > diff --git a/checkpolicy/test/dismod.c b/checkpolicy/test/dismod.c
> > index fa7117f5..5995e135 100644
> > --- a/checkpolicy/test/dismod.c
> > +++ b/checkpolicy/test/dismod.c
> > @@ -564,13 +564,25 @@ static void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp
> >
> >  static void display_filename_trans(filename_trans_rule_t * tr, policydb_t * p, FILE * fp)
> >  {
> > +       const char *match_str = "";
> >         fprintf(fp, "filename transition");
> >         for (; tr; tr = tr->next) {
> >                 display_type_set(&tr->stypes, 0, p, fp);
> >                 display_type_set(&tr->ttypes, 0, p, fp);
> >                 display_id(p, fp, SYM_CLASSES, tr->tclass - 1, ":");
> >                 display_id(p, fp, SYM_TYPES, tr->otype - 1, "");
> > -               fprintf(fp, " %s\n", tr->name);
> > +               switch (tr->match_type) {
> > +               case FILENAME_TRANS_MATCH_EXACT:
> > +                       match_str = "";
> > +                       break;
> > +               case FILENAME_TRANS_MATCH_PREFIX:
> > +                       match_str = " prefix";
> > +                       break;
> > +               case FILENAME_TRANS_MATCH_SUFFIX:
> > +                       match_str = " suffix";
> > +                       break;
> > +               }
> > +               fprintf(fp, " %s%s\n", tr->name, match_str);
> >         }
> >  }
> >
> > diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c
> > index b567ce77..4426b844 100644
> > --- a/checkpolicy/test/dispol.c
> > +++ b/checkpolicy/test/dispol.c
> > @@ -450,6 +450,7 @@ static void display_role_trans(policydb_t *p, FILE *fp)
> >
> >  struct filenametr_display_args {
> >         policydb_t *p;
> > +       uint32_t match_type;
> >         FILE *fp;
> >  };
> >
> > @@ -464,6 +465,19 @@ static int filenametr_display(hashtab_key_t key,
> >         FILE *fp = args->fp;
> >         ebitmap_node_t *node;
> >         uint32_t bit;
> > +       const char *match_str = "";
> > +
> > +       switch (args->match_type) {
> > +       case FILENAME_TRANS_MATCH_EXACT:
> > +               match_str = "";
> > +               break;
> > +       case FILENAME_TRANS_MATCH_PREFIX:
> > +               match_str = " prefix";
> > +               break;
> > +       case FILENAME_TRANS_MATCH_SUFFIX:
> > +               match_str = " suffix";
> > +               break;
> > +       }
> >
> >         do {
> >                 ebitmap_for_each_positive_bit(&ftdatum->stypes, node, bit) {
> > @@ -471,7 +485,7 @@ static int filenametr_display(hashtab_key_t key,
> >                         display_id(p, fp, SYM_TYPES, ft->ttype - 1, "");
> >                         display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":");
> >                         display_id(p, fp, SYM_TYPES, ftdatum->otype - 1, "");
> > -                       fprintf(fp, " %s\n", ft->name);
> > +                       fprintf(fp, " %s%s\n", ft->name, match_str);
> >                 }
> >                 ftdatum = ftdatum->next;
> >         } while (ftdatum);
> > @@ -487,7 +501,15 @@ static void display_filename_trans(policydb_t *p, FILE *fp)
> >         fprintf(fp, "filename_trans rules:\n");
> >         args.p = p;
> >         args.fp = fp;
> > -       hashtab_map(p->filename_trans, filenametr_display, &args);
> > +       args.match_type = FILENAME_TRANS_MATCH_EXACT;
> > +       hashtab_map(p->filename_trans[FILENAME_TRANS_MATCH_EXACT],
> > +                   filenametr_display, &args);
> > +       args.match_type = FILENAME_TRANS_MATCH_PREFIX;
> > +       hashtab_map(p->filename_trans[FILENAME_TRANS_MATCH_PREFIX],
> > +                   filenametr_display, &args);
> > +       args.match_type = FILENAME_TRANS_MATCH_SUFFIX;
> > +       hashtab_map(p->filename_trans[FILENAME_TRANS_MATCH_SUFFIX],
> > +                   filenametr_display, &args);
> >  }
> >
> >  static int menu(void)
> > diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
> > index 2021187d..37769fc4 100644
> > --- a/libsepol/cil/src/cil.c
> > +++ b/libsepol/cil/src/cil.c
> > @@ -97,6 +97,8 @@ char *CIL_KEY_TUNABLEIF;
> >  char *CIL_KEY_ALLOW;
> >  char *CIL_KEY_DONTAUDIT;
> >  char *CIL_KEY_TYPETRANSITION;
> > +char *CIL_KEY_PREFIX;
> > +char *CIL_KEY_SUFFIX;
> >  char *CIL_KEY_TYPECHANGE;
> >  char *CIL_KEY_CALL;
> >  char *CIL_KEY_TUNABLE;
> > @@ -269,6 +271,8 @@ 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_PREFIX = cil_strpool_add("prefix");
> > +       CIL_KEY_SUFFIX = cil_strpool_add("suffix");
> >         CIL_KEY_TYPECHANGE = cil_strpool_add("typechange");
> >         CIL_KEY_CALL = cil_strpool_add("call");
> >         CIL_KEY_TUNABLE = cil_strpool_add("tunable");
> > @@ -2456,6 +2460,8 @@ void cil_nametypetransition_init(struct cil_nametypetransition **nametypetrans)
> >         (*nametypetrans)->obj = NULL;
> >         (*nametypetrans)->name_str = NULL;
> >         (*nametypetrans)->name = NULL;
> > +       (*nametypetrans)->match_type_str = NULL;
> > +       (*nametypetrans)->match_type = FILENAME_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 a8e3616a..75a9e064 100644
> > --- a/libsepol/cil/src/cil_binary.c
> > +++ b/libsepol/cil/src/cil_binary.c
> > @@ -1168,7 +1168,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, uint32_t match_type,
> >                                                 type_datum_t *sepol_result)
> >  {
> >         int rc;
> > @@ -1183,7 +1183,7 @@ static int __cil_typetransition_to_avtab_helper(policydb_t *pdb,
> >                 rc = policydb_filetrans_insert(
> >                         pdb, sepol_src->s.value, sepol_tgt->s.value,
> >                         sepol_obj->s.value, name, NULL,
> > -                       sepol_result->s.value, &otype
> > +                       sepol_result->s.value, match_type, &otype
> >                 );
> >                 if (rc != SEPOL_OK) {
> >                         if (rc == SEPOL_EEXIST) {
> > @@ -1252,7 +1252,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->match_type, sepol_result
> >                         );
> >                         if (rc != SEPOL_OK) goto exit;
> >                 }
> > @@ -1270,7 +1270,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->match_type, 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 8976c254..94dadef8 100644
> > --- a/libsepol/cil/src/cil_build_ast.c
> > +++ b/libsepol/cil/src/cil_build_ast.c
> > @@ -3392,10 +3392,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;
> > @@ -3411,12 +3412,22 @@ 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 = parse_current->next->next->next->next->next->data;
> > +                       }
> >                 }
> >         }
> >
> > @@ -3428,8 +3439,13 @@ 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->name_str = s4;
> > +               if (s6) {
> > +                       nametypetrans->match_type_str = s5;
> > +                       nametypetrans->result_str = s6;
> > +               } else {
> > +                       nametypetrans->result_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 bc972f03..300390ec 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->match_type_str = orig->match_type_str;
> >         new->result_str = orig->result_str;
> >
> >
> > diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
> > index 9e492cb9..7f0be652 100644
> > --- a/libsepol/cil/src/cil_internal.h
> > +++ b/libsepol/cil/src/cil_internal.h
> > @@ -114,6 +114,8 @@ extern char *CIL_KEY_TUNABLEIF;
> >  extern char *CIL_KEY_ALLOW;
> >  extern char *CIL_KEY_DONTAUDIT;
> >  extern char *CIL_KEY_TYPETRANSITION;
> > +extern char *CIL_KEY_PREFIX;
> > +extern char *CIL_KEY_SUFFIX;
> >  extern char *CIL_KEY_TYPECHANGE;
> >  extern char *CIL_KEY_CALL;
> >  extern char *CIL_KEY_TUNABLE;
> > @@ -580,6 +582,8 @@ struct cil_nametypetransition {
> >         struct cil_class *obj;
> >         char *name_str;
> >         struct cil_name *name;
> > +       char *match_type_str;
> > +       uint32_t match_type;
> >         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..9776dfd3 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 *match_type_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->match_type) {
> > +               case FILENAME_TRANS_MATCH_EXACT:
> > +                       match_type_str = "";
> > +                       break;
> > +               case FILENAME_TRANS_MATCH_PREFIX:
> > +                       match_type_str = " prefix";
> > +                       break;
> > +               case FILENAME_TRANS_MATCH_SUFFIX:
> > +                       match_type_str = " suffix";
> > +                       break;
> > +               default:
> > +                       match_type_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, match_type_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 33b9d321..3b00f065 100644
> > --- a/libsepol/cil/src/cil_resolve_ast.c
> > +++ b/libsepol/cil/src/cil_resolve_ast.c
> > @@ -717,6 +717,18 @@ int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_ar
> >                 nametypetrans->name = (struct cil_name *)name_datum;
> >         }
> >
> > +       if (nametypetrans->match_type_str == NULL) {
> > +               nametypetrans->match_type = FILENAME_TRANS_MATCH_EXACT;
> > +       } else if (nametypetrans->match_type_str == CIL_KEY_PREFIX) {
> > +               nametypetrans->match_type = FILENAME_TRANS_MATCH_PREFIX;
> > +       } else if (nametypetrans->match_type_str == CIL_KEY_SUFFIX) {
> > +               nametypetrans->match_type = FILENAME_TRANS_MATCH_SUFFIX;
> > +       } else {
> > +               cil_tree_log(current, CIL_ERR, "Invalid name match type \"%s\"", nametypetrans->match_type_str);
> > +               rc = SEPOL_ERR;
> > +               goto exit;
> > +       }
> > +
> >         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 4da7a77c..99c82292 100644
> > --- a/libsepol/cil/src/cil_write_ast.c
> > +++ b/libsepol/cil/src/cil_write_ast.c
> > @@ -1178,6 +1178,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->match_type != FILENAME_TRANS_MATCH_EXACT)
> > +                       fprintf(out, "%s ", rule->match_type_str);
> >                 fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str));
> >                 fprintf(out, ")\n");
> >                 break;
> > diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
> > index 6682069e..7727ca52 100644
> > --- a/libsepol/include/sepol/policydb/policydb.h
> > +++ b/libsepol/include/sepol/policydb/policydb.h
> > @@ -321,6 +321,7 @@ typedef struct filename_trans_rule {
> >         uint32_t tclass;
> >         char *name;
> >         uint32_t otype; /* new type */
> > +       uint32_t match_type;

Maybe add a name for the added enum and mention it here in a comment.

> >         struct filename_trans_rule *next;
> >  } filename_trans_rule_t;
> >
> > @@ -423,6 +424,14 @@ typedef struct genfs {
> >  /* OCON_NUM needs to be the largest index in any platform's ocontext array */
> >  #define OCON_NUM   9
> >
> > +/* filename transitions table array indices */
> > +enum {
> > +       FILENAME_TRANS_MATCH_EXACT,
> > +       FILENAME_TRANS_MATCH_PREFIX,
> > +       FILENAME_TRANS_MATCH_SUFFIX,
> > +       FILENAME_TRANS_MATCH_NUM,
> > +};
> > +
> >  /* section: module information */
> >
> >  /* scope_index_t holds all of the symbols that are in scope in a
> > @@ -593,7 +602,7 @@ typedef struct policydb {
> >         hashtab_t range_tr;
> >
> >         /* file transitions with the last path component */
> > -       hashtab_t filename_trans;
> > +       hashtab_t filename_trans[FILENAME_TRANS_MATCH_NUM];
> >         uint32_t filename_trans_count;
> >
> >         ebitmap_t *type_attr_map;
> > @@ -657,7 +666,8 @@ extern int policydb_sort_ocontexts(policydb_t *p);
> >  extern int policydb_filetrans_insert(policydb_t *p, uint32_t stype,
> >                                      uint32_t ttype, uint32_t tclass,
> >                                      const char *name, char **name_alloc,
> > -                                    uint32_t otype, uint32_t *present_otype);
> > +                                    uint32_t otype, uint32_t match_type,
> > +                                    uint32_t *present_otype);
> >
> >  /* Deprecated */
> >  extern int policydb_context_isvalid(const policydb_t * p,
> > @@ -758,10 +768,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
> >  #define POLICYDB_VERSION_INFINIBAND            31 /* Linux-specific */
> >  #define POLICYDB_VERSION_GLBLUB                32
> >  #define POLICYDB_VERSION_COMP_FTRANS   33 /* compressed filename transitions */
> > +#define POLICYDB_VERSION_PREFIX_SUFFIX 34 /* prefix and suffix filename transitions */
> >
> >  /* Range of policy versions we understand*/
> >  #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
> > -#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_COMP_FTRANS
> > +#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_PREFIX_SUFFIX
> >
> >  /* Module versions and specific changes*/
> >  #define MOD_POLICYDB_VERSION_BASE              4
> > @@ -784,9 +795,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
> >  #define MOD_POLICYDB_VERSION_INFINIBAND                19
> >  #define MOD_POLICYDB_VERSION_GLBLUB            20
> >  #define MOD_POLICYDB_VERSION_SELF_TYPETRANS    21
> > +#define MOD_POLICYDB_VERSION_PREFIX_SUFFIX     22
> >
> >  #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
> > -#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_SELF_TYPETRANS
> > +#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PREFIX_SUFFIX
> >
> >  #define POLICYDB_CONFIG_MLS    1
> >
> > diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
> > index ee5f9185..4df9521a 100644
> > --- a/libsepol/src/expand.c
> > +++ b/libsepol/src/expand.c
> > @@ -1419,18 +1419,31 @@ static int expand_filename_trans_helper(expand_state_t *state,
> >         rc = policydb_filetrans_insert(
> >                 state->out, s + 1, t + 1,
> >                 rule->tclass, rule->name,
> > -               NULL, mapped_otype, &present_otype
> > +               NULL, mapped_otype, rule->match_type, &present_otype
> >         );
> >         if (rc == SEPOL_EEXIST) {
> >                 /* duplicate rule, ignore */
> >                 if (present_otype == mapped_otype)
> >                         return 0;
> >
> > -               ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\":  %s vs %s",
> > +               const char *match_str = "";
> > +               switch (rule->match_type) {
> > +               case FILENAME_TRANS_MATCH_EXACT:
> > +                       match_str = "";
> > +                       break;
> > +               case FILENAME_TRANS_MATCH_PREFIX:
> > +                       match_str = " prefix";
> > +                       break;
> > +               case FILENAME_TRANS_MATCH_SUFFIX:
> > +                       match_str = " suffix";
> > +                       break;
> > +               }
> > +               ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\"%s:  %s vs %s",
> >                     state->out->p_type_val_to_name[s],
> >                     state->out->p_type_val_to_name[t],
> >                     state->out->p_class_val_to_name[rule->tclass - 1],
> >                     rule->name,
> > +                   match_str,
> >                     state->out->p_type_val_to_name[present_otype - 1],
> >                     state->out->p_type_val_to_name[mapped_otype - 1]);
> >                 return -1;
> > diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
> > index 8fcc385d..81efeaa2 100644
> > --- a/libsepol/src/kernel_to_cil.c
> > +++ b/libsepol/src/kernel_to_cil.c
> > @@ -1869,6 +1869,7 @@ exit:
> >
> >  struct map_filename_trans_args {
> >         struct policydb *pdb;
> > +       uint32_t match_type;
> >         struct strs *strs;
> >  };
> >
> > @@ -1883,6 +1884,19 @@ static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
> >         struct ebitmap_node *node;
> >         uint32_t bit;
> >         int rc;
> > +       const char *match_str = "";
> > +
> > +       switch (map_args->match_type) {
> > +       case FILENAME_TRANS_MATCH_EXACT:
> > +               match_str = "";
> > +               break;
> > +       case FILENAME_TRANS_MATCH_PREFIX:
> > +               match_str = " prefix";
> > +               break;
> > +       case FILENAME_TRANS_MATCH_SUFFIX:
> > +               match_str = " suffix";
> > +               break;
> > +       }
> >
> >         tgt = pdb->p_type_val_to_name[ft->ttype - 1];
> >         class = pdb->p_class_val_to_name[ft->tclass - 1];
> > @@ -1893,8 +1907,8 @@ static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
> >                 ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
> >                         src = pdb->p_type_val_to_name[bit];
> >                         rc = strs_create_and_add(strs,
> > -                                                "(typetransition %s %s %s \"%s\" %s)",
> > -                                                5, src, tgt, class, filename, new);
> > +                                                "(typetransition %s %s %s \"%s\"%s %s)",
> > +                                                6, src, tgt, class, filename, match_str, new);
> >                         if (rc)
> >                                 return rc;
> >                 }
> > @@ -1919,7 +1933,23 @@ static int write_filename_trans_rules_to_cil(FILE *out, struct policydb *pdb)
> >         args.pdb = pdb;
> >         args.strs = strs;
> >
> > -       rc = hashtab_map(pdb->filename_trans, map_filename_trans_to_str, &args);
> > +       args.match_type = FILENAME_TRANS_MATCH_EXACT;
> > +       rc = hashtab_map(pdb->filename_trans[FILENAME_TRANS_MATCH_EXACT],
> > +                        map_filename_trans_to_str, &args);
> > +       if (rc != 0) {
> > +               goto exit;
> > +       }
> > +
> > +       args.match_type = FILENAME_TRANS_MATCH_PREFIX;
> > +       rc = hashtab_map(pdb->filename_trans[FILENAME_TRANS_MATCH_PREFIX],
> > +                        map_filename_trans_to_str, &args);
> > +       if (rc != 0) {
> > +               goto exit;
> > +       }
> > +
> > +       args.match_type = FILENAME_TRANS_MATCH_SUFFIX;
> > +       rc = hashtab_map(pdb->filename_trans[FILENAME_TRANS_MATCH_SUFFIX],
> > +                        map_filename_trans_to_str, &args);
> >         if (rc != 0) {
> >                 goto exit;
> >         }
> > diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
> > index b0ae16d9..99bef76e 100644
> > --- a/libsepol/src/kernel_to_conf.c
> > +++ b/libsepol/src/kernel_to_conf.c
> > @@ -1845,6 +1845,7 @@ exit:
> >
> >  struct map_filename_trans_args {
> >         struct policydb *pdb;
> > +       uint32_t match_type;
> >         struct strs *strs;
> >  };
> >
> > @@ -1859,6 +1860,19 @@ static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
> >         struct ebitmap_node *node;
> >         uint32_t bit;
> >         int rc;
> > +       const char *match_str = "";
> > +
> > +       switch (map_args->match_type) {
> > +       case FILENAME_TRANS_MATCH_EXACT:
> > +               match_str = "";
> > +               break;
> > +       case FILENAME_TRANS_MATCH_PREFIX:
> > +               match_str = " prefix";
> > +               break;
> > +       case FILENAME_TRANS_MATCH_SUFFIX:
> > +               match_str = " suffix";
> > +               break;
> > +       }
> >
> >         tgt = pdb->p_type_val_to_name[ft->ttype - 1];
> >         class = pdb->p_class_val_to_name[ft->tclass - 1];
> > @@ -1869,8 +1883,8 @@ static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
> >                 ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
> >                         src = pdb->p_type_val_to_name[bit];
> >                         rc = strs_create_and_add(strs,
> > -                                                "type_transition %s %s:%s %s \"%s\";",
> > -                                                5, src, tgt, class, new, filename);
> > +                                                "type_transition %s %s:%s %s \"%s\"%s;",
> > +                                                6, src, tgt, class, new, filename, match_str);
> >                         if (rc)
> >                                 return rc;
> >                 }
> > @@ -1895,7 +1909,23 @@ static int write_filename_trans_rules_to_conf(FILE *out, struct policydb *pdb)
> >         args.pdb = pdb;
> >         args.strs = strs;
> >
> > -       rc = hashtab_map(pdb->filename_trans, map_filename_trans_to_str, &args);
> > +       args.match_type = FILENAME_TRANS_MATCH_EXACT;
> > +       rc = hashtab_map(pdb->filename_trans[FILENAME_TRANS_MATCH_EXACT],
> > +                        map_filename_trans_to_str, &args);
> > +       if (rc != 0) {
> > +               goto exit;
> > +       }
> > +
> > +       args.match_type = FILENAME_TRANS_MATCH_PREFIX;
> > +       rc = hashtab_map(pdb->filename_trans[FILENAME_TRANS_MATCH_PREFIX],
> > +                        map_filename_trans_to_str, &args);
> > +       if (rc != 0) {
> > +               goto exit;
> > +       }
> > +
> > +       args.match_type = FILENAME_TRANS_MATCH_SUFFIX;
> > +       rc = hashtab_map(pdb->filename_trans[FILENAME_TRANS_MATCH_SUFFIX],
> > +                        map_filename_trans_to_str, &args);
> >         if (rc != 0) {
> >                 goto exit;
> >         }
> > diff --git a/libsepol/src/link.c b/libsepol/src/link.c
> > index 3b7742bc..f432087f 100644
> > --- a/libsepol/src/link.c
> > +++ b/libsepol/src/link.c
> > @@ -1440,6 +1440,7 @@ static int copy_filename_trans_list(filename_trans_rule_t * list,
> >                 new_rule->name = strdup(cur->name);
> >                 if (!new_rule->name)
> >                         goto err;
> > +               new_rule->match_type = cur->match_type;
> >
> >                 if (type_set_or_convert(&cur->stypes, &new_rule->stypes, module) ||
> >                     type_set_or_convert(&cur->ttypes, &new_rule->ttypes, module))
> > diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c
> > index d2868019..98e1c7ba 100644
> > --- a/libsepol/src/module_to_cil.c
> > +++ b/libsepol/src/module_to_cil.c
> > @@ -1609,6 +1609,7 @@ static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filena
> >         unsigned int ttype;
> >         struct type_set *ts;
> >         struct filename_trans_rule *rule;
> > +       const char *match_str = "";
> >
> >         for (rule = rules; rule != NULL; rule = rule->next) {
> >                 ts = &rule->stypes;
> > @@ -1623,19 +1624,31 @@ static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filena
> >                         goto exit;
> >                 }
> >
> > +               switch (rule->match_type) {
> > +               case FILENAME_TRANS_MATCH_EXACT:
> > +                       match_str = "";
> > +                       break;
> > +               case FILENAME_TRANS_MATCH_PREFIX:
> > +                       match_str = " prefix";
> > +                       break;
> > +               case FILENAME_TRANS_MATCH_SUFFIX:
> > +                       match_str = " suffix";
> > +                       break;
> > +               }
> > +
> >                 for (stype = 0; stype < num_stypes; stype++) {
> >                         for (ttype = 0; ttype < num_ttypes; ttype++) {
> > -                               cil_println(indent, "(typetransition %s %s %s \"%s\" %s)",
> > +                               cil_println(indent, "(typetransition %s %s %s \"%s\"%s %s)",
> >                                             stypes[stype], ttypes[ttype],
> >                                             pdb->p_class_val_to_name[rule->tclass - 1],
> > -                                           rule->name,
> > +                                           rule->name, match_str,
> >                                             pdb->p_type_val_to_name[rule->otype - 1]);
> >                         }
> >                         if (rule->flags & RULE_SELF) {
> > -                               cil_println(indent, "(typetransition %s self %s \"%s\" %s)",
> > +                               cil_println(indent, "(typetransition %s self %s \"%s\"%s %s)",
> >                                             stypes[stype],
> >                                             pdb->p_class_val_to_name[rule->tclass - 1],
> > -                                           rule->name,
> > +                                           rule->name, match_str,
> >                                             pdb->p_type_val_to_name[rule->otype - 1]);
> >                         }
> >                 }
> > diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
> > index f9537caa..29d7971a 100644
> > --- a/libsepol/src/policydb.c
> > +++ b/libsepol/src/policydb.c
> > @@ -208,6 +208,13 @@ static const struct policydb_compat_info policydb_compat[] = {
> >          .ocon_num = OCON_IBENDPORT + 1,
> >          .target_platform = SEPOL_TARGET_SELINUX,
> >         },
> > +       {
> > +        .type = POLICY_KERN,
> > +        .version = POLICYDB_VERSION_PREFIX_SUFFIX,
> > +        .sym_num = SYM_NUM,
> > +        .ocon_num = OCON_IBENDPORT + 1,
> > +        .target_platform = SEPOL_TARGET_SELINUX,
> > +       },
> >         {
> >          .type = POLICY_BASE,
> >          .version = MOD_POLICYDB_VERSION_BASE,
> > @@ -334,6 +341,13 @@ static const struct policydb_compat_info policydb_compat[] = {
> >          .ocon_num = OCON_IBENDPORT + 1,
> >          .target_platform = SEPOL_TARGET_SELINUX,
> >         },
> > +       {
> > +        .type = POLICY_BASE,
> > +        .version = MOD_POLICYDB_VERSION_PREFIX_SUFFIX,
> > +        .sym_num = SYM_NUM,
> > +        .ocon_num = OCON_IBENDPORT + 1,
> > +        .target_platform = SEPOL_TARGET_SELINUX,
> > +       },
> >         {
> >          .type = POLICY_MOD,
> >          .version = MOD_POLICYDB_VERSION_BASE,
> > @@ -460,6 +474,13 @@ static const struct policydb_compat_info policydb_compat[] = {
> >          .ocon_num = 0,
> >          .target_platform = SEPOL_TARGET_SELINUX,
> >         },
> > +       {
> > +        .type = POLICY_MOD,
> > +        .version = MOD_POLICYDB_VERSION_PREFIX_SUFFIX,
> > +        .sym_num = SYM_NUM,
> > +        .ocon_num = 0,
> > +        .target_platform = SEPOL_TARGET_SELINUX,
> > +       },
> >  };
> >
> >  #if 0
> > @@ -909,10 +930,14 @@ int policydb_init(policydb_t * p)
> >         if (rc)
> >                 goto err;
> >
> > -       p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
> > -       if (!p->filename_trans) {
> > -               rc = -ENOMEM;
> > -               goto err;
> > +       for (i = 0; i < FILENAME_TRANS_MATCH_NUM; i++) {
> > +               p->filename_trans[i] = hashtab_create(filenametr_hash,
> > +                                                     filenametr_cmp,
> > +                                                     (1 << 10));
> > +               if (!p->filename_trans[i]) {
> > +                       rc = -ENOMEM;
> > +                       goto err;
> > +               }
> >         }
> >
> >         p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
> > @@ -926,7 +951,9 @@ int policydb_init(policydb_t * p)
> >
> >         return 0;
> >  err:
> > -       hashtab_destroy(p->filename_trans);
> > +       for (i = 0; i < FILENAME_TRANS_MATCH_NUM; i++) {
> > +               hashtab_destroy(p->filename_trans[i]);
> > +       }
> >         hashtab_destroy(p->range_tr);
> >         for (i = 0; i < SYM_NUM; i++) {
> >                 hashtab_destroy(p->symtab[i].table);
> > @@ -1564,8 +1591,10 @@ void policydb_destroy(policydb_t * p)
> >         if (lra)
> >                 free(lra);
> >
> > -       hashtab_map(p->filename_trans, filenametr_destroy, NULL);
> > -       hashtab_destroy(p->filename_trans);
> > +       for (i = 0; i < FILENAME_TRANS_MATCH_NUM; i++) {
> > +               hashtab_map(p->filename_trans[i], filenametr_destroy, NULL);
> > +               hashtab_destroy(p->filename_trans[i]);
> > +       }
> >
> >         hashtab_map(p->range_tr, range_tr_destroy, NULL);
> >         hashtab_destroy(p->range_tr);
> > @@ -2599,7 +2628,7 @@ static int role_allow_read(role_allow_t ** r, struct policy_file *fp)
> >  int policydb_filetrans_insert(policydb_t *p, uint32_t stype, uint32_t ttype,
> >                               uint32_t tclass, const char *name,
> >                               char **name_alloc, uint32_t otype,
> > -                             uint32_t *present_otype)
> > +                             uint32_t match_type, uint32_t *present_otype)
> >  {
> >         filename_trans_key_t *ft, key;
> >         filename_trans_datum_t *datum, *last;
> > @@ -2609,7 +2638,8 @@ int policydb_filetrans_insert(policydb_t *p, uint32_t stype, uint32_t ttype,
> >         key.name = (char *)name;
> >
> >         last = NULL;
> > -       datum = hashtab_search(p->filename_trans, (hashtab_key_t)&key);
> > +       datum = hashtab_search(p->filename_trans[match_type],
> > +                              (hashtab_key_t)&key);
> >         while (datum) {
> >                 if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
> >                         if (present_otype)
> > @@ -2657,7 +2687,8 @@ int policydb_filetrans_insert(policydb_t *p, uint32_t stype, uint32_t ttype,
> >                         ft->tclass = tclass;
> >                         ft->name = name_dup;
> >
> > -                       if (hashtab_insert(p->filename_trans, (hashtab_key_t)ft,
> > +                       if (hashtab_insert(p->filename_trans[match_type],
> > +                                          (hashtab_key_t)ft,
> >                                            (hashtab_datum_t)datum)) {
> >                                 free(name_dup);
> >                                 free(datum);
> > @@ -2704,8 +2735,9 @@ static int filename_trans_read_one_compat(policydb_t *p, struct policy_file *fp)
> >         tclass = le32_to_cpu(buf[2]);
> >         otype  = le32_to_cpu(buf[3]);
> >
> > +       // This version does not contain other than exact filename transitions
> >         rc = policydb_filetrans_insert(p, stype, ttype, tclass, name, &name,
> > -                                      otype, NULL);
> > +                                      otype, FILENAME_TRANS_MATCH_EXACT, NULL);
> >         if (rc) {
> >                 if (rc != SEPOL_EEXIST)
> >                         goto err;
> > @@ -2753,7 +2785,8 @@ out:
> >         return rc;
> >  }
> >
> > -static int filename_trans_read_one(policydb_t *p, struct policy_file *fp)
> > +static int filename_trans_read_one(policydb_t *p, uint32_t match_type,
> > +                                  struct policy_file *fp)
> >  {
> >         filename_trans_key_t *ft = NULL;
> >         filename_trans_datum_t **dst, *datum, *first = NULL;
> > @@ -2823,7 +2856,7 @@ static int filename_trans_read_one(policydb_t *p, struct policy_file *fp)
> >         ft->tclass = tclass;
> >         ft->name = name;
> >
> > -       rc = hashtab_insert(p->filename_trans, (hashtab_key_t)ft,
> > +       rc = hashtab_insert(p->filename_trans[match_type], (hashtab_key_t)ft,
> >                             (hashtab_datum_t)first);
> >         if (rc)
> >                 goto err;
> > @@ -2842,7 +2875,8 @@ err:
> >         return -1;
> >  }
> >
> > -static int filename_trans_read(policydb_t *p, struct policy_file *fp)
> > +static int filename_trans_read(policydb_t *p, struct policy_file *fp,
> > +                              uint32_t match_type)
> >  {
> >         unsigned int i;
> >         uint32_t buf[1], nel;
> > @@ -2855,13 +2889,17 @@ static int filename_trans_read(policydb_t *p, struct policy_file *fp)
> >
> >         if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
> >                 for (i = 0; i < nel; i++) {
> > +                       /*
> > +                        * this version does not have other than exact match
> > +                        * transitions
> > +                        */
> >                         rc = filename_trans_read_one_compat(p, fp);
> >                         if (rc < 0)
> >                                 return -1;
> >                 }
> >         } else {
> >                 for (i = 0; i < nel; i++) {
> > -                       rc = filename_trans_read_one(p, fp);
> > +                       rc = filename_trans_read_one(p, match_type, fp);
> >                         if (rc < 0)
> >                                 return -1;
> >                 }
> > @@ -3837,7 +3875,7 @@ static int role_allow_rule_read(role_allow_rule_t ** r, struct policy_file *fp)
> >  static int filename_trans_rule_read(policydb_t *p, filename_trans_rule_t **r,
> >                                     struct policy_file *fp)
> >  {
> > -       uint32_t buf[3], nel, i, len;
> > +       uint32_t buf[4], nel, i, len;
> >         unsigned int entries;
> >         filename_trans_rule_t *ftr, *lftr;
> >         int rc;
> > @@ -3883,7 +3921,9 @@ static int filename_trans_rule_read(policydb_t *p, filename_trans_rule_t **r,
> >                 if (type_set_read(&ftr->ttypes, fp))
> >                         return -1;
> >
> > -               if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS)
> > +               if (p->policyvers >= MOD_POLICYDB_VERSION_PREFIX_SUFFIX)
> > +                       entries = 4;
> > +               else if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS)
> >                         entries = 3;
> >                 else
> >                         entries = 2;
> > @@ -3895,6 +3935,8 @@ static int filename_trans_rule_read(policydb_t *p, filename_trans_rule_t **r,
> >                 ftr->otype = le32_to_cpu(buf[1]);
> >                 if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS)
> >                         ftr->flags = le32_to_cpu(buf[2]);
> > +               if (p->policyvers >=  MOD_POLICYDB_VERSION_PREFIX_SUFFIX)
> > +                       ftr->match_type = le32_to_cpu(buf[3]);
> >         }
> >
> >         return 0;
> > @@ -4470,7 +4512,11 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
> >                 if (role_allow_read(&p->role_allow, fp))
> >                         goto bad;
> >                 if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS &&
> > -                   filename_trans_read(p, fp))
> > +                   filename_trans_read(p, fp, FILENAME_TRANS_MATCH_EXACT))
> > +                       goto bad;
> > +               if (r_policyvers >= POLICYDB_VERSION_PREFIX_SUFFIX &&
> > +                   (filename_trans_read(p, fp, FILENAME_TRANS_MATCH_PREFIX) ||
> > +                    filename_trans_read(p, fp, FILENAME_TRANS_MATCH_SUFFIX)))
> >                         goto bad;
> >         } else {
> >                 /* first read the AV rule blocks, then the scope tables */
> > diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c
>
> Unfortunately, the patch to validate policy capabilities that I merged
> yesterday causes problems in this part of your patch.
>
> > index 892a0ffd..3f2ba5ea 100644
> > --- a/libsepol/src/policydb_validate.c
> > +++ b/libsepol/src/policydb_validate.c
> > @@ -1,4 +1,3 @@
> > -
> >  #include <sepol/policydb/conditional.h>
> >  #include <sepol/policydb/ebitmap.h>
> >  #include <sepol/policydb/policydb.h>
>
> polcaps.h header was added before the policydb.h header
>
> > @@ -1115,14 +1114,27 @@ bad:
> >         return -1;
> >  }
> >
> > -static int validate_filename_trans_hashtab(sepol_handle_t *handle, hashtab_t filename_trans, validate_t flavors[])
> > +static int validate_filename_trans_hashtabs(sepol_handle_t *handle,
> > +                                           const policydb_t *p,
> > +                                           validate_t flavors[])
>
> The polcaps patch actually gives you what you want here already.
>
> >  {
> > -       if (hashtab_map(filename_trans, validate_filename_trans, flavors)) {
> > -               ERR(handle, "Invalid filename trans");
> > -               return -1;
>
> This has changed.
>
> > +       if (hashtab_map(p->filename_trans[FILENAME_TRANS_MATCH_EXACT],
> > +                       validate_filename_trans, flavors))
> > +               goto bad;
> > +
> > +       if (p->policyvers >= POLICYDB_VERSION_PREFIX_SUFFIX) {
> > +               if (hashtab_map(p->filename_trans[FILENAME_TRANS_MATCH_PREFIX],
> > +                               validate_filename_trans, flavors))
> > +                       goto bad;
> > +               if (hashtab_map(p->filename_trans[FILENAME_TRANS_MATCH_SUFFIX],
> > +                               validate_filename_trans, flavors))
> > +                       goto bad;
> >         }
> >
> >         return 0;
> > +bad:
> > +       ERR(handle, "Invalid filename trans");
> > +       return -1;
> >  }
> >
> >  static int validate_context(const context_struct_t *con, validate_t flavors[], int mls)
> > @@ -1334,6 +1346,15 @@ static int validate_filename_trans_rules(sepol_handle_t *handle, const filename_
> >                 if (validate_simpletype(filename_trans->otype, p, flavors))
> >                         goto bad;
> >
> > +               switch (filename_trans->match_type) {
> > +               case FILENAME_TRANS_MATCH_EXACT:
> > +               case FILENAME_TRANS_MATCH_PREFIX:
> > +               case FILENAME_TRANS_MATCH_SUFFIX:
> > +                       break;
> > +               default:
> > +                       goto bad;
> > +               }
> > +
> >                 /* currently only the RULE_SELF flag can be set */
> >                 if ((filename_trans->flags & ~RULE_SELF) != 0)
> >                         goto bad;
> > @@ -1554,9 +1575,10 @@ int policydb_validate(sepol_handle_t *handle, const policydb_t *p)
> >                         goto bad;
> >                 if (validate_role_allows(handle, p->role_allow, flavors))
> >                         goto bad;
> > -               if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS)
> > -                       if (validate_filename_trans_hashtab(handle, p->filename_trans, flavors))
> > +               if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) {
> > +                       if (validate_filename_trans_hashtabs(handle, p, flavors))
> >                                 goto bad;
> > +               }
>
> Your change is very similar to what the polcap patch already did.
>
> The needed changes should be fairly straightforward.
> Thanks,
> Jim
>
>
> >         } else {
> >                 if (validate_avrule_blocks(handle, p->global, p, flavors))
> >                         goto bad;
> > diff --git a/libsepol/src/write.c b/libsepol/src/write.c
> > index 283d11c8..c9398a98 100644
> > --- a/libsepol/src/write.c
> > +++ b/libsepol/src/write.c
> > @@ -653,7 +653,8 @@ static int filename_write_one(hashtab_key_t key, void *data, void *ptr)
> >         return 0;
> >  }
> >
> > -static int filename_trans_write(struct policydb *p, void *fp)
> > +static int filename_trans_write(struct policydb *p, uint32_t match_type,
> > +                               void *fp)
> >  {
> >         size_t items;
> >         uint32_t buf[1];
> > @@ -663,20 +664,25 @@ static int filename_trans_write(struct policydb *p, void *fp)
> >                 return 0;
> >
> >         if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
> > +               /*
> > +                * This version does not have other than exact match
> > +                * transitions, there is no need to count other ones.
> > +                */
> >                 buf[0] = cpu_to_le32(p->filename_trans_count);
> >                 items = put_entry(buf, sizeof(uint32_t), 1, fp);
> >                 if (items != 1)
> >                         return POLICYDB_ERROR;
> >
> > -               rc = hashtab_map(p->filename_trans, filename_write_one_compat,
> > -                                fp);
> > +               rc = hashtab_map(p->filename_trans[match_type],
> > +                                filename_write_one_compat, fp);
> >         } else {
> > -               buf[0] = cpu_to_le32(p->filename_trans->nel);
> > +               buf[0] = cpu_to_le32(p->filename_trans[match_type]->nel);
> >                 items = put_entry(buf, sizeof(uint32_t), 1, fp);
> >                 if (items != 1)
> >                         return POLICYDB_ERROR;
> >
> > -               rc = hashtab_map(p->filename_trans, filename_write_one, fp);
> > +               rc = hashtab_map(p->filename_trans[match_type],
> > +                                filename_write_one, fp);
> >         }
> >         return rc;
> >  }
> > @@ -1944,7 +1950,7 @@ static int filename_trans_rule_write(policydb_t *p, filename_trans_rule_t *t,
> >  {
> >         int nel = 0;
> >         size_t items, entries;
> > -       uint32_t buf[3], len;
> > +       uint32_t buf[4], len;
> >         filename_trans_rule_t *ftr;
> >
> >         for (ftr = t; ftr; ftr = ftr->next)
> > @@ -1974,8 +1980,11 @@ static int filename_trans_rule_write(policydb_t *p, filename_trans_rule_t *t,
> >                 buf[0] = cpu_to_le32(ftr->tclass);
> >                 buf[1] = cpu_to_le32(ftr->otype);
> >                 buf[2] = cpu_to_le32(ftr->flags);
> > +               buf[3] = cpu_to_le32(ftr->match_type);
> >
> > -               if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) {
> > +               if (p->policyvers >= MOD_POLICYDB_VERSION_PREFIX_SUFFIX) {
> > +                       entries = 4;
> > +               } else if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) {
> >                         entries = 3;
> >                 } else if (!(ftr->flags & RULE_SELF)) {
> >                         entries = 2;
> > @@ -2370,12 +2379,29 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
> >                 if (role_allow_write(p->role_allow, fp))
> >                         return POLICYDB_ERROR;
> >                 if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) {
> > -                       if (filename_trans_write(p, fp))
> > +                       if (filename_trans_write(p, FILENAME_TRANS_MATCH_EXACT,
> > +                                                fp))
> >                                 return POLICYDB_ERROR;
> >                 } else {
> > -                       if (p->filename_trans)
> > +                       if (p->filename_trans[FILENAME_TRANS_MATCH_EXACT])
> >                                 WARN(fp->handle, "Discarding filename type transition rules");
> >                 }
> > +               if (p->policyvers >= POLICYDB_VERSION_PREFIX_SUFFIX) {
> > +                       if (filename_trans_write(p, FILENAME_TRANS_MATCH_PREFIX,
> > +                                                fp) ||
> > +                           filename_trans_write(p, FILENAME_TRANS_MATCH_SUFFIX,
> > +                                                fp))
> > +                               return POLICYDB_ERROR;
> > +               } else {
> > +                       if (p->filename_trans[FILENAME_TRANS_MATCH_PREFIX] &&
> > +                           p->filename_trans[FILENAME_TRANS_MATCH_PREFIX]->nel)
> > +                               WARN(fp->handle,
> > +                                    "Discarding prefix filename type transition rules");
> > +                       if (p->filename_trans[FILENAME_TRANS_MATCH_SUFFIX] &&
> > +                           p->filename_trans[FILENAME_TRANS_MATCH_SUFFIX]->nel)
> > +                               WARN(fp->handle,
> > +                                    "Discarding suffix filename type transition rules");
> > +               }
> >         } else {
> >                 if (avrule_block_write(p->global, num_syms, p, fp) == -1) {
> >                         return POLICYDB_ERROR;
> > --
> > 2.41.0
> >




[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux