Skip to content

Commit

Permalink
checkpolicy,libsepol: add prefix/suffix matching to filename type tra…
Browse files Browse the repository at this point in the history
…nsitions

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]: TODO: PASTE LINK

Signed-off-by: Juraj Marcin <[email protected]>
  • Loading branch information
JurajMarcin committed Nov 8, 2023
1 parent 6df403d commit c6deff4
Show file tree
Hide file tree
Showing 23 changed files with 367 additions and 68 deletions.
7 changes: 4 additions & 3 deletions checkpolicy/policy_define.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion checkpolicy/policy_define.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 12 additions & 1 deletion checkpolicy/policy_parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 ';'
Expand Down Expand Up @@ -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 ';'
Expand Down
4 changes: 4 additions & 0 deletions checkpolicy/policy_scan.l
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down
14 changes: 13 additions & 1 deletion checkpolicy/test/dismod.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
26 changes: 24 additions & 2 deletions checkpolicy/test/dispol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand All @@ -464,14 +465,27 @@ 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) {
display_id(p, fp, SYM_TYPES, bit, "");
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);
Expand All @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions libsepol/cil/src/cil.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
}
Expand Down
8 changes: 4 additions & 4 deletions libsepol/cil/src/cil_binary.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down
26 changes: 21 additions & 5 deletions libsepol/cil/src/cil_build_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
}
}

Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions libsepol/cil/src/cil_copy_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;


Expand Down
4 changes: 4 additions & 0 deletions libsepol/cil/src/cil_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */

Expand Down
17 changes: 16 additions & 1 deletion libsepol/cil/src/cil_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down
12 changes: 12 additions & 0 deletions libsepol/cil/src/cil_resolve_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions libsepol/cil/src/cil_write_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit c6deff4

Please sign in to comment.