Skip to content

Commit

Permalink
libsepol: add compile-time constraint for mutual exclusive attributes
Browse files Browse the repository at this point in the history
Add a new compile-time constraint, similar to neverallow, which enables
to specify two or more type attributes to be mutual exclusive.  This
means no type can be associated with more than one of them.

The constraints are stored as a linked-list in the policy for modular
policies, by a new modular policy version, and are discarded in kernel
policies, not needing any kernel support.

Some Reference Policy examples:

    unpriv_userdomain, admindomain:

        <no violations>

    client_packet_type, server_packet_type:

        <no violations>

    auth_file_type, non_auth_file_type:

        <no violations>

    pseudofs, xattrfs, noxattrfs:

         <no violations>

    reserved_port_type, unreserved_port_type:

         <no violations>

    security_file_type, non_security_file_type:

        libsepol.check_segregate_attributes: Segregate Attributes violation, type dnssec_t associated with attributes security_file_type and non_security_file_type

    ibendport_type, packet_type, sysctl_type, device_node, ibpkey_type,
    sysfs_types, domain, boolean_type, netif_type, file_type, node_type,
    proc_type, port_type:

        libsepol.check_segregate_attributes: Segregate Attributes violation, type sysctl_fs_t associated with attributes sysctl_type and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type sysctl_t associated with attributes sysctl_type and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type virt_content_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type initrc_devpts_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type qemu_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type user_devpts_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type cardmgr_dev_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type bootloader_tmp_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type xen_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type svirt_prot_exec_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type xen_devpts_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type svirt_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type virt_image_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type container_file_t associated with attributes device_node and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type cpu_online_t associated with attributes sysfs_types and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type sysfs_t associated with attributes sysfs_types and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type dockerc_t associated with attributes domain and file_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type proc_t associated with attributes file_type and proc_type
        libsepol.check_segregate_attributes: Segregate Attributes violation, type proc_xen_t associated with attributes file_type and proc_type

    libsepol.check_assertions: 20 Segregate Attributes failures occurred

Closes: SELinuxProject#42

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
v3:
   - drop source location information:
     this information was already lost for binary modular policies and
     CIL policies; also typeattribute statements have none and the few
     segregate_attributes statements can be easily grepped
   - misc renaming
v2:
   rebase onto _after suffix change
  • Loading branch information
cgzones committed Nov 23, 2022
1 parent f033218 commit d37be9d
Show file tree
Hide file tree
Showing 8 changed files with 325 additions and 13 deletions.
15 changes: 14 additions & 1 deletion libsepol/include/sepol/policydb/policydb.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ typedef struct type_datum {
uint32_t bounds; /* bounds type, if exist */
} type_datum_t;

/* Mutual exclusive attributes */
typedef struct segregate_attributes_rule {
ebitmap_t attrs; /* mutual exclusive attributes */
struct segregate_attributes_rule *next;
} segregate_attributes_rule_t;

/*
* Properties of type_datum
* available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
Expand Down Expand Up @@ -605,6 +611,10 @@ typedef struct policydb {
bitmaps. Someday the 0 bit may be used for global permissive */
ebitmap_t permissive_map;

/* mutual exclusive attributes (not preserved in kernel policy).
stored as linked list */
segregate_attributes_rule_t *segregate_attributes;

unsigned policyvers;

unsigned handle_unknown;
Expand Down Expand Up @@ -696,6 +706,8 @@ extern void level_datum_init(level_datum_t * x);
extern void level_datum_destroy(level_datum_t * x);
extern void cat_datum_init(cat_datum_t * x);
extern void cat_datum_destroy(cat_datum_t * x);
extern void segregate_attributes_rule_init(segregate_attributes_rule_t * x);
extern void segregate_attributes_rule_destroy(segregate_attributes_rule_t * x);
extern int check_assertion(policydb_t *p, avrule_t *avrule);
extern int check_assertions(sepol_handle_t * handle,
policydb_t * p, avrule_t * avrules);
Expand Down Expand Up @@ -783,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_SEGREGATE_ATTRIBUTES 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_SEGREGATE_ATTRIBUTES

#define POLICYDB_CONFIG_MLS 1

Expand Down
57 changes: 49 additions & 8 deletions libsepol/src/assertion.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct avtab_match_args {
unsigned long errors;
};

static const char* policy_name(policydb_t *p) {
static const char* policy_name(const policydb_t *p) {
const char *policy_file = "policy.conf";
if (p->name) {
policy_file = p->name;
Expand Down Expand Up @@ -535,20 +535,51 @@ int check_assertion(policydb_t *p, avrule_t *avrule)
return rc;
}

static int check_segregate_attributes(sepol_handle_t *handle, const policydb_t *p)
{
const segregate_attributes_rule_t *sattr;
int errors = 0, rc;

for (sattr = p->segregate_attributes; sattr; sattr = sattr->next) {
ebitmap_node_t *first_node;
unsigned int first_bit;

ebitmap_for_each_positive_bit(&sattr->attrs, first_node, first_bit) {
ebitmap_node_t *second_node;
unsigned int second_bit;

ebitmap_for_each_positive_bit_after(&sattr->attrs, second_node, second_bit, first_node, first_bit) {
ebitmap_t attr_union;
ebitmap_node_t *type_node;
unsigned int type_bit;

rc = ebitmap_and(&attr_union, &p->attr_type_map[first_bit], &p->attr_type_map[second_bit]);
if (rc < 0)
return rc;

ebitmap_for_each_positive_bit(&attr_union, type_node, type_bit) {
ERR(handle, "Segregate Attributes violation, type %s associated with attributes %s and %s",
p->p_type_val_to_name[type_bit],
p->p_type_val_to_name[first_bit],
p->p_type_val_to_name[second_bit]);
errors++;
}

ebitmap_destroy(&attr_union);
}
}
}

return errors;
}

int check_assertions(sepol_handle_t * handle, policydb_t * p,
avrule_t * avrules)
{
int rc;
avrule_t *a;
unsigned long errors = 0;

if (!avrules) {
/* Since assertions are stored in avrules, if it is NULL
there won't be any to check. This also prevents an invalid
free if the avtabs are never initialized */
return 0;
}

for (a = avrules; a != NULL; a = a->next) {
if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
continue;
Expand All @@ -570,5 +601,15 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
if (errors)
ERR(handle, "%lu neverallow failures occurred", errors);

rc = check_segregate_attributes(handle, p);
if (rc < 0) {
ERR(handle, "Error occurred while checking Segregate Attributes");
return -1;
}
if (rc) {
ERR(handle, "%d Segregate Attributes failures occurred", rc);
errors += rc;
}

return errors ? -1 : 0;
}
45 changes: 44 additions & 1 deletion libsepol/src/expand.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ static void expand_state_init(expand_state_t * state)
memset(state, 0, sizeof(expand_state_t));
}

static int map_ebitmap(ebitmap_t * src, ebitmap_t * dst, uint32_t * map)
static int map_ebitmap(const ebitmap_t * src, ebitmap_t * dst, const uint32_t * map)
{
unsigned int i;
ebitmap_node_t *tnode;
Expand Down Expand Up @@ -2341,6 +2341,45 @@ static int genfs_copy(expand_state_t * state)
return 0;
}

static int segregate_attributes_copy(expand_state_t *state)
{
const segregate_attributes_rule_t *old;
segregate_attributes_rule_t *list = NULL;

for (old = state->base->segregate_attributes; old; old = old->next) {
segregate_attributes_rule_t *new;

new = malloc(sizeof(segregate_attributes_rule_t));
if (!new) {
ERR(state->handle, "Out of memory!");
return -1;
}

segregate_attributes_rule_init(new);

if (map_ebitmap(&old->attrs, &new->attrs, state->typemap)) {
ERR(state->handle, "out of memory");
ebitmap_destroy(&new->attrs);
free(new);
return -1;
}

if (list)
list->next = new;
else {
if (state->out->segregate_attributes) {
segregate_attributes_rule_t *s;
for (s = state->out->segregate_attributes; s->next; s = s->next) {}
s->next = new;
} else
state->out->segregate_attributes = new;
}
list = new;
}

return 0;
}

static int type_attr_map(hashtab_key_t key
__attribute__ ((unused)), hashtab_datum_t datum,
void *ptr)
Expand Down Expand Up @@ -3173,6 +3212,10 @@ int expand_module(sepol_handle_t * handle,
if (genfs_copy(&state))
goto cleanup;

/* copy segregate attributes */
if (segregate_attributes_copy(&state))
goto cleanup;

/* Build the type<->attribute maps and remove attributes. */
state.out->attr_type_map = calloc(state.out->p_types.nprim,
sizeof(ebitmap_t));
Expand Down
38 changes: 37 additions & 1 deletion libsepol/src/kernel_to_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,33 @@ static int write_avtab_to_conf(FILE *out, struct policydb *pdb, int indent)
return rc;
}

static int write_segregate_attributes_to_conf(FILE *out, const struct policydb *pdb)
{
const segregate_attributes_rule_t *sattr;

for (sattr = pdb->segregate_attributes; sattr; sattr = sattr->next) {
struct ebitmap_node *node;
unsigned int bit;
int first = 1;

sepol_printf(out, "segregate_attributes ");

ebitmap_for_each_positive_bit(&sattr->attrs, node, bit) {
if (first) {
first = 0;
} else {
sepol_printf(out, ", ");
}

sepol_printf(out, "%s", pdb->p_type_val_to_name[bit - 1]);
}

sepol_printf(out, ";\n");
}

return 0;
}

struct map_filename_trans_args {
struct policydb *pdb;
struct strs *strs;
Expand Down Expand Up @@ -3200,7 +3227,16 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
if (rc != 0) {
goto exit;
}
write_filename_trans_rules_to_conf(out, pdb);

rc = write_segregate_attributes_to_conf(out, pdb);
if (rc != 0) {
goto exit;
}

rc = write_filename_trans_rules_to_conf(out, pdb);
if (rc != 0) {
goto exit;
}

if (pdb->mls) {
rc = write_range_trans_rules_to_conf(out, pdb);
Expand Down
44 changes: 44 additions & 0 deletions libsepol/src/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,45 @@ static int scope_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
return -1;
}

static int copy_segregate_attributes(link_state_t * state, const policy_module_t *module)
{
const segregate_attributes_rule_t *src_sattr;
segregate_attributes_rule_t *list = NULL;

for (src_sattr = module->policy->segregate_attributes; src_sattr; src_sattr = src_sattr->next) {
segregate_attributes_rule_t *new_sattr;

new_sattr = malloc(sizeof(segregate_attributes_rule_t));
if (!new_sattr) {
ERR(state->handle, "Out of memory!");
return -1;
}

segregate_attributes_rule_init(new_sattr);

if (ebitmap_convert(&src_sattr->attrs, &new_sattr->attrs, module->map[SYM_TYPES])) {
ebitmap_destroy(&new_sattr->attrs);
free(new_sattr);
ERR(state->handle, "Out of memory!");
return -1;
}

if (list)
list->next = new_sattr;
else {
if (state->base->segregate_attributes) {
segregate_attributes_rule_t *s;
for (s = state->base->segregate_attributes; s->next; s = s->next) {}
s->next = new_sattr;
} else
state->base->segregate_attributes = new_sattr;
}
list = new_sattr;
}

return 0;
}

/* Copy a module over to a base, remapping all values within. After
* all identifiers and rules are done, copy the scoping information.
* This is when it checks for duplicate declarations. */
Expand Down Expand Up @@ -1891,6 +1930,11 @@ static int copy_module(link_state_t * state, policy_module_t * module)
}
}

ret = copy_segregate_attributes(state, module);
if (ret) {
return ret;
}

return 0;
}

Expand Down
Loading

0 comments on commit d37be9d

Please sign in to comment.