checkpolicy,libsepol: add prefix/suffix support to module policy

This patch extends the structures for module and base policy (avrule_t)
to support prefix/suffix transitions. In addition to this, it implements
the necessary changes to functions for reading and writing the binary
policy, as well as parsing the policy conf.

Syntax of the new prefix/suffix filename transition rule:

    type_transition source_type target_type : class default_type object_name match_type;

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;

Reviewed-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Juraj Marcin <juraj@jurajmarcin.com>
Acked-by: James Carter <jwcart2@gmail.com>
This commit is contained in:
Juraj Marcin 2023-06-20 11:01:22 +02:00 committed by James Carter
parent 1174483d29
commit c39ebd07ac
16 changed files with 150 additions and 43 deletions

View File

@ -1601,7 +1601,8 @@ static int set_types(type_set_t * set, char *id, int *add, char starallowed)
return -1;
}
static int define_compute_type_helper(int which, avrule_t ** rule, int has_filename)
static int define_compute_type_helper(int which, avrule_t ** rule,
int has_filename, uint8_t name_match)
{
char *id;
type_datum_t *datum;
@ -1676,6 +1677,7 @@ static int define_compute_type_helper(int which, avrule_t ** rule, int has_filen
goto bad;
}
}
avrule->name_match = name_match;
ebitmap_for_each_positive_bit(&tclasses, node, i) {
perm = malloc(sizeof(class_perm_node_t));
@ -1700,7 +1702,7 @@ static int define_compute_type_helper(int which, avrule_t ** rule, int has_filen
return -1;
}
int define_compute_type(int which, int has_filename)
int define_compute_type(int which, int has_filename, uint8_t name_match)
{
char *id;
avrule_t *avrule;
@ -1721,7 +1723,8 @@ int define_compute_type(int which, int has_filename)
return 0;
}
if (define_compute_type_helper(which, &avrule, has_filename))
if (define_compute_type_helper(which, &avrule, has_filename,
name_match))
return -1;
append_avrule(avrule);
@ -1745,7 +1748,8 @@ avrule_t *define_cond_compute_type(int which)
return (avrule_t *) 1;
}
if (define_compute_type_helper(which, &avrule, 0))
if (define_compute_type_helper(which, &avrule, 0,
NAME_TRANS_MATCH_EXACT))
return COND_ERR;
return avrule;
@ -2394,6 +2398,7 @@ static int avrule_cpy(avrule_t *dest, const avrule_t *src)
return -1;
}
}
dest->name_match = src->name_match;
dest->line = src->line;
dest->source_filename = strdup(source_file);
if (!dest->source_filename) {

View File

@ -28,7 +28,7 @@ int define_default_role(int which);
int define_default_type(int which);
int define_default_range(int which);
int define_common_perms(void);
int define_compute_type(int which, int has_filename);
int define_compute_type(int which, int has_filename, uint8_t name_match);
int define_conditional(cond_expr_t *expr, avrule_t *t_list, avrule_t *f_list );
int define_constraint(constraint_expr_t *expr);
int define_dominance(void);

View File

@ -108,6 +108,7 @@ typedef int (* require_func_t)(int pass);
%token IF
%token ELSE
%token TYPE_TRANSITION
%token PREFIX SUFFIX
%token TYPE_MEMBER
%token TYPE_CHANGE
%token ROLE_TRANSITION
@ -451,13 +452,17 @@ cond_dontaudit_def : DONTAUDIT names names ':' names names ';'
;
;
transition_def : TYPE_TRANSITION names names ':' names identifier filename ';'
{if (define_compute_type(AVRULE_TRANSITION, 1)) return -1; }
{if (define_compute_type(AVRULE_TRANSITION, 1, NAME_TRANS_MATCH_EXACT)) return -1;}
| TYPE_TRANSITION names names ':' names identifier filename PREFIX ';'
{if (define_compute_type(AVRULE_TRANSITION, 1, NAME_TRANS_MATCH_PREFIX)) return -1;}
| TYPE_TRANSITION names names ':' names identifier filename SUFFIX ';'
{if (define_compute_type(AVRULE_TRANSITION, 1, NAME_TRANS_MATCH_SUFFIX)) return -1;}
| TYPE_TRANSITION names names ':' names identifier ';'
{if (define_compute_type(AVRULE_TRANSITION, 0)) return -1;}
{if (define_compute_type(AVRULE_TRANSITION, 0, NAME_TRANS_MATCH_EXACT)) return -1;}
| TYPE_MEMBER names names ':' names identifier ';'
{if (define_compute_type(AVRULE_MEMBER, 0)) return -1;}
{if (define_compute_type(AVRULE_MEMBER, 0, NAME_TRANS_MATCH_EXACT)) return -1;}
| TYPE_CHANGE names names ':' names identifier ';'
{if (define_compute_type(AVRULE_CHANGE, 0)) return -1;}
{if (define_compute_type(AVRULE_CHANGE, 0, NAME_TRANS_MATCH_EXACT)) return -1;}
;
range_trans_def : RANGE_TRANSITION names names mls_range_def ';'
{ if (define_range_trans(0)) return -1; }

View File

@ -123,6 +123,10 @@ EXPANDATTRIBUTE |
expandattribute { return(EXPANDATTRIBUTE); }
TYPE_TRANSITION |
type_transition { return(TYPE_TRANSITION); }
PREFIX |
prefix { return(PREFIX); }
SUFFIX |
suffix { return(SUFFIX); }
TYPE_MEMBER |
type_member { return(TYPE_MEMBER); }
TYPE_CHANGE |

View File

@ -345,6 +345,20 @@ static int display_avrule(avrule_t * avrule, policydb_t * policy,
display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, "");
if (avrule->object_name)
fprintf(fp, " \"%s\"", avrule->object_name);
switch (avrule->name_match) {
case NAME_TRANS_MATCH_EXACT:
/* do nothing */
break;
case NAME_TRANS_MATCH_PREFIX:
fprintf(fp, " PREFIX");
break;
case NAME_TRANS_MATCH_SUFFIX:
fprintf(fp, " SUFFIX");
break;
default:
fprintf(fp, " ERROR: no valid name match type specified\n");
return -1;
}
} else if (avrule->specified & AVRULE_XPERMS) {
avtab_extended_perms_t xperms;
int i;

View File

@ -129,7 +129,7 @@ typedef struct {
avtab_key_t *key;
policydb_t *p;
FILE *fp;
name_trans_match_t match;
uint8_t match;
} render_name_trans_args_t;
static int render_name_trans_helper(hashtab_key_t k, hashtab_datum_t d, void *a)

View File

@ -1211,7 +1211,8 @@ 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, &otype);
sepol_result->s.value, name, NAME_TRANS_MATCH_EXACT,
&otype);
if (rc != SEPOL_OK) {
if (rc == SEPOL_EEXIST) {
if (sepol_result->s.value!= otype) {
@ -4651,6 +4652,7 @@ static avrule_t *__cil_init_sepol_avrule(uint32_t kind, struct cil_tree_node *no
__cil_init_sepol_type_set(&avrule->ttypes);
avrule->perms = NULL;
avrule->object_name = NULL;
avrule->name_match = NAME_TRANS_MATCH_EXACT;
avrule->line = node->line;
avrule->source_filename = NULL;

View File

@ -156,6 +156,7 @@ extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified);
extern int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key,
uint32_t otype, const char *name,
uint8_t name_match,
uint32_t *present_otype);
extern int avtab_filename_trans_read(void *fp, uint32_t vers, avtab_t *a);

View File

@ -252,12 +252,6 @@ typedef struct av_extended_perms {
uint32_t perms[EXTENDED_PERMS_LEN];
} av_extended_perms_t;
typedef enum name_trans_match {
NAME_TRANS_MATCH_EXACT,
NAME_TRANS_MATCH_PREFIX,
NAME_TRANS_MATCH_SUFFIX,
} name_trans_match_t;
typedef struct avrule {
/* these typedefs are almost exactly the same as those in avtab.h - they are
* here because of the need to include neverallow and dontaudit messages */
@ -285,6 +279,10 @@ typedef struct avrule {
type_set_t ttypes;
class_perm_node_t *perms;
char *object_name; /* optional object name */
#define NAME_TRANS_MATCH_EXACT 0
#define NAME_TRANS_MATCH_PREFIX 1
#define NAME_TRANS_MATCH_SUFFIX 2
uint8_t name_match;
av_extended_perms_t *xperms;
unsigned long line; /* line number from policy.conf where
* this rule originated */
@ -757,9 +755,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
#define MOD_POLICYDB_VERSION_GLBLUB 20
#define MOD_POLICYDB_VERSION_SELF_TYPETRANS 21
#define MOD_POLICYDB_VERSION_AVRULE_FTRANS 22
#define MOD_POLICYDB_VERSION_PREFIX_SUFFIX 23 /* preffix/suffix support for filename transitions */
#define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_AVRULE_FTRANS
#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PREFIX_SUFFIX
#define POLICYDB_CONFIG_MLS 1

View File

@ -771,7 +771,7 @@ int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers)
int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key,
uint32_t otype, const char *name,
uint32_t *present_otype)
uint8_t name_match, uint32_t *present_otype)
{
int rc = SEPOL_ENOMEM;
avtab_trans_t new_trans = {0};
@ -780,6 +780,7 @@ int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key,
avtab_ptr_t node;
char *name_key = NULL;
uint32_t *otype_datum = NULL;
symtab_t *target_symtab;
datum = avtab_search(a, key);
if (!datum) {
@ -793,8 +794,22 @@ int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key,
datum = &node->datum;
}
if (!datum->trans->name_trans.table) {
rc = symtab_init(&datum->trans->name_trans, 1 << 8);
switch (name_match) {
case NAME_TRANS_MATCH_EXACT:
target_symtab = &datum->trans->name_trans;
break;
case NAME_TRANS_MATCH_PREFIX:
target_symtab = &datum->trans->prefix_trans;
break;
case NAME_TRANS_MATCH_SUFFIX:
target_symtab = &datum->trans->suffix_trans;
break;
default:
return SEPOL_ERR;
}
if (!target_symtab->table) {
rc = symtab_init(target_symtab, 1 << 8);
if (rc < 0)
return rc;
}
@ -810,8 +825,7 @@ int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key,
goto bad;
*otype_datum = otype;
rc = hashtab_insert(datum->trans->name_trans.table, name_key,
otype_datum);
rc = hashtab_insert(target_symtab->table, name_key, otype_datum);
if (rc < 0)
goto bad;
@ -856,7 +870,8 @@ static int filename_trans_read_one(avtab_t *a, void *fp)
key.target_class = le32_to_cpu(buf[2]);
otype = le32_to_cpu(buf[3]);
rc = avtab_insert_filename_trans(a, &key, otype, name, NULL);
rc = avtab_insert_filename_trans(a, &key, otype, name,
NAME_TRANS_MATCH_EXACT, NULL);
if (rc)
goto err;
@ -909,7 +924,8 @@ static int filename_trans_comp_read_one(avtab_t *a, void *fp)
key.source_type = bit + 1;
rc = avtab_insert_filename_trans(a, &key, otype, name,
NULL);
NAME_TRANS_MATCH_EXACT,
NULL);
if (rc < 0)
goto err_ebitmap;
}

View File

@ -1620,7 +1620,8 @@ static int expand_terule_helper(sepol_handle_t * handle,
uint32_t specified, cond_av_list_t ** cond,
cond_av_list_t ** other, uint32_t stype,
uint32_t ttype, class_perm_node_t * perms,
char *object_name, avtab_t * avtab, int enabled)
char *object_name, uint8_t name_match,
avtab_t * avtab, int enabled)
{
avtab_key_t avkey;
avtab_datum_t *avdatump;
@ -1652,6 +1653,7 @@ static int expand_terule_helper(sepol_handle_t * handle,
int rc = avtab_insert_filename_trans(avtab, &avkey,
remapped_data,
object_name,
name_match,
&oldtype);
if (rc == SEPOL_EEXIST) {
ERR(handle, "conflicting filename transition %s %s:%s \"%s\": %s vs %s",
@ -1885,6 +1887,7 @@ static int expand_rule_helper(sepol_handle_t * handle,
source_rule->specified, cond,
other, i, i, source_rule->perms,
source_rule->object_name,
source_rule->name_match,
dest_avtab, enabled);
if (retval != EXPAND_RULE_SUCCESS)
return retval;
@ -1902,6 +1905,7 @@ static int expand_rule_helper(sepol_handle_t * handle,
source_rule->specified, cond,
other, i, j, source_rule->perms,
source_rule->object_name,
source_rule->name_match,
dest_avtab, enabled);
if (retval != EXPAND_RULE_SUCCESS)
return retval;

View File

@ -90,7 +90,7 @@ typedef struct {
const char *src;
const char *tgt;
const char *class;
name_trans_match_t match;
uint8_t match;
} name_trans_to_strs_args_t;
void sepol_indent(FILE *out, int indent);

View File

@ -1254,6 +1254,7 @@ static int copy_avrule_list(avrule_t * list, avrule_t ** dst,
if (!new_rule->object_name)
goto cleanup;
}
new_rule->name_match = cur->name_match;
cur_perm = cur->perms;
tail_perm = NULL;

View File

@ -547,12 +547,13 @@ static int semantic_level_to_cil(struct policydb *pdb, int sens_offset, struct m
return 0;
}
static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const char *object_name, const struct class_perm_node *classperms)
static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const char *object_name, uint8_t name_match, const struct class_perm_node *classperms)
{
int rc = -1;
const char *rule;
const struct class_perm_node *classperm;
char *perms;
const char *match_str = "";
switch (type) {
case AVRULE_ALLOWED:
@ -598,10 +599,24 @@ static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const
pdb->p_class_val_to_name[classperm->tclass - 1],
perms + 1);
} else if (object_name) {
cil_println(indent, "(%s %s %s %s \"%s\" %s)",
switch (name_match) {
case NAME_TRANS_MATCH_EXACT:
match_str = "";
break;
case NAME_TRANS_MATCH_PREFIX:
match_str = " prefix";
break;
case NAME_TRANS_MATCH_SUFFIX:
match_str = " suffix";
break;
default:
ERR(NULL, "Unknown name match type: %" PRIu8,
name_match);
}
cil_println(indent, "(%s %s %s %s \"%s\"%s %s)",
rule, src, tgt,
pdb->p_class_val_to_name[classperm->tclass - 1],
object_name,
object_name, match_str,
pdb->p_type_val_to_name[classperm->data - 1]);
} else {
cil_println(indent, "(%s %s %s %s %s)",
@ -1205,7 +1220,7 @@ static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *a
if (avrule->specified & AVRULE_XPERMS) {
rc = avrulex_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms, avrule->xperms);
} else {
rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->object_name, avrule->perms);
rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->object_name, avrule->name_match, avrule->perms);
}
if (rc != 0) {
goto exit;
@ -1216,7 +1231,7 @@ static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *a
if (avrule->specified & AVRULE_XPERMS) {
rc = avrulex_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms, avrule->xperms);
} else {
rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->object_name, avrule->perms);
rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->object_name, avrule->name_match, avrule->perms);
}
if (rc != 0) {
goto exit;

View File

@ -355,6 +355,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,
@ -488,6 +495,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
@ -3171,6 +3185,7 @@ common_read, class_read, role_read, type_read, user_read,
static avrule_t *avrule_read(policydb_t * p, struct policy_file *fp)
{
unsigned int i;
uint8_t buf8;
uint32_t buf[2], len;
class_perm_node_t *cur, *tail = NULL;
avrule_t *avrule;
@ -3234,10 +3249,15 @@ static avrule_t *avrule_read(policydb_t * p, struct policy_file *fp)
if (rc < 0)
goto bad;
}
if (p->policyvers >= MOD_POLICYDB_VERSION_PREFIX_SUFFIX) {
rc = next_entry(&buf8, fp, sizeof(uint8_t));
if (rc < 0)
goto bad;
avrule->name_match = buf8;
}
}
if (avrule->specified & AVRULE_XPERMS) {
uint8_t buf8;
size_t nel = ARRAY_SIZE(avrule->xperms->perms);
uint32_t buf32[nel];
@ -3546,6 +3566,7 @@ static int filename_trans_rule_read(policydb_t *p, avrule_t **r,
rc = str_read(&cur->object_name, fp, len);
if (rc)
return -1;
cur->name_match = NAME_TRANS_MATCH_EXACT;
if (type_set_read(&cur->stypes, fp))
return -1;

View File

@ -2071,6 +2071,7 @@ static int avrule_write(policydb_t *p, avrule_t * avrule,
struct policy_file *fp)
{
size_t items, items2;
uint8_t buf8;
uint32_t buf[32], len;
class_perm_node_t *cur;
@ -2078,6 +2079,11 @@ static int avrule_write(policydb_t *p, avrule_t * avrule,
if (p->policyvers < MOD_POLICYDB_VERSION_AVRULE_FTRANS &&
avrule->specified & AVRULE_TRANSITION && avrule->object_name)
return POLICYDB_SUCCESS;
/* skip prefix/suffix name transition if writing older version */
if (p->policyvers < MOD_POLICYDB_VERSION_PREFIX_SUFFIX &&
avrule->specified & AVRULE_TRANSITION &&
avrule->object_name && avrule->name_match != NAME_TRANS_MATCH_EXACT)
return POLICYDB_SUCCESS;
if (p->policyvers < MOD_POLICYDB_VERSION_SELF_TYPETRANS &&
(avrule->specified & AVRULE_TYPE) &&
@ -2136,12 +2142,17 @@ static int avrule_write(policydb_t *p, avrule_t * avrule,
if (items != len)
return POLICYDB_ERROR;
}
if (p->policyvers >= MOD_POLICYDB_VERSION_PREFIX_SUFFIX) {
buf8 = avrule->name_match;
items = put_entry(&buf8, sizeof(uint8_t), 1, fp);
if (items != 1)
return POLICYDB_ERROR;
}
}
if (avrule->specified & AVRULE_XPERMS) {
size_t nel = ARRAY_SIZE(avrule->xperms->perms);
uint32_t buf32[nel];
uint8_t buf8;
unsigned int i;
if (p->policyvers < MOD_POLICYDB_VERSION_XPERMS_IOCTL) {
@ -2186,12 +2197,17 @@ static int avrule_write_list(policydb_t *p, avrule_t * avrules,
avrule = avrules;
len = 0;
while (avrule) {
if (p->policyvers >= MOD_POLICYDB_VERSION_AVRULE_FTRANS ||
!(avrule->specified & AVRULE_TRANSITION &&
avrule->object_name))
len++;
avrule = avrule->next;
for (avrule = avrules; avrule; avrule = avrule->next) {
if (p->policyvers < MOD_POLICYDB_VERSION_AVRULE_FTRANS &&
(avrule->specified & AVTAB_TRANSITION) &&
avrule->object_name)
continue;
if (p->policyvers < MOD_POLICYDB_VERSION_PREFIX_SUFFIX &&
(avrule->specified & AVTAB_TRANSITION) &&
avrule->object_name &&
avrule->name_match != NAME_TRANS_MATCH_EXACT)
continue;
len++;
}
buf[0] = cpu_to_le32(len);
@ -2299,7 +2315,8 @@ static int filename_trans_rule_write(policydb_t *p, avrule_t *rules,
class_perm_node_t *perm;
for (rule = rules; rule; rule = rule->next) {
if (rule->specified & AVRULE_TRANSITION && rule->object_name) {
if (rule->specified & AVRULE_TRANSITION && rule->object_name &&
rule->name_match == NAME_TRANS_MATCH_EXACT) {
for (perm = rule->perms; perm; perm = perm->next) {
nel++;
}
@ -2312,7 +2329,9 @@ static int filename_trans_rule_write(policydb_t *p, avrule_t *rules,
return POLICYDB_ERROR;
for (rule = rules; rule; rule = rule->next) {
if (!(rule->specified & AVRULE_TRANSITION && rule->object_name))
if (!(rule->specified & AVRULE_TRANSITION &&
rule->object_name &&
rule->name_match == NAME_TRANS_MATCH_EXACT))
continue;
len = strlen(rule->object_name);
for (perm = rule->perms; perm; perm = perm->next) {
@ -2751,7 +2770,8 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
if (p->policy_type == POLICY_KERN) {
if (avtab_write(p, &p->te_avtab, fp))
return POLICYDB_ERROR;
if (avtab_has_prefix_suffix_filename_transitions(&p->te_avtab)) {
if (p->policyvers < POLICYDB_VERSION_PREFIX_SUFFIX &&
avtab_has_prefix_suffix_filename_transitions(&p->te_avtab)) {
WARN(fp->handle,
"Discarding filename prefix/suffix type transition rules");
}