Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disjoint Attributes Rule #359

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Prev Previous commit
Next Next commit
libsepol: add compile-time constraint for mutual exclusive attributes
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_disjoint_attributes: Disjoint Attributes Rule 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_disjoint_attributes: Disjoint Attributes Rule violation, type sysctl_fs_t associated with attributes sysctl_type and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type sysctl_t associated with attributes sysctl_type and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type virt_content_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type initrc_devpts_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type qemu_image_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type user_devpts_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type cardmgr_dev_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type bootloader_tmp_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type xen_image_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type svirt_prot_exec_image_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type xen_devpts_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type svirt_image_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type virt_image_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type container_file_t associated with attributes device_node and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type cpu_online_t associated with attributes sysfs_types and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type sysfs_t associated with attributes sysfs_types and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type dockerc_t associated with attributes domain and file_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type proc_t associated with attributes file_type and proc_type
        libsepol.check_disjoint_attributes: Disjoint Attributes Rule violation, type proc_xen_t associated with attributes file_type and proc_type

    libsepol.check_assertions: 20 Disjoint Attributes Rule failures occurred

Closes: #42

Signed-off-by: Christian Göttsche <[email protected]>
---
v4:
   rename to disjoint attributes
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 Apr 29, 2024
commit 054e921d033f6e57cd0a3f2c597e96fc8af2749a
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 disjoint_attributes_rule {
ebitmap_t attrs; /* mutual exclusive attributes */
struct disjoint_attributes_rule *next;
} disjoint_attributes_rule_t;

/*
* Properties of type_datum
* available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
Expand Down Expand Up @@ -606,6 +612,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 */
disjoint_attributes_rule_t *disjoint_attributes;

unsigned policyvers;

unsigned handle_unknown;
Expand Down Expand Up @@ -697,6 +707,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 disjoint_attributes_rule_init(disjoint_attributes_rule_t * x);
extern void disjoint_attributes_rule_destroy(disjoint_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 @@ -784,9 +796,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_DISJOINT_ATTRIBUTES 22 /* disjoint attributes compile time constraint */

#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_DISJOINT_ATTRIBUTES

#define POLICYDB_CONFIG_MLS 1

Expand Down
66 changes: 54 additions & 12 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 @@ -146,7 +146,7 @@ static void extended_permissions_violated(avtab_extended_perms_t *result,
}

/* Same scenarios of interest as check_assertion_extended_permissions */
static int report_assertion_extended_permissions(sepol_handle_t *handle,
static unsigned long report_assertion_extended_permissions(sepol_handle_t *handle,
policydb_t *p, const avrule_t *avrule,
unsigned int stype, unsigned int ttype,
const class_perm_node_t *curperm, uint32_t perms,
Expand All @@ -162,7 +162,7 @@ static int report_assertion_extended_permissions(sepol_handle_t *handle,
unsigned int i, j;
int rc;
int found_xperm = 0;
int errors = 0;
unsigned long errors = 0;

memcpy(&tmp_key, k, sizeof(avtab_key_t));
tmp_key.specified = AVTAB_XPERMS_ALLOWED;
Expand Down Expand Up @@ -319,7 +319,7 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void
return rc;
}

static int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
static long int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
{
int rc;
struct avtab_match_args args;
Expand Down Expand Up @@ -640,20 +640,52 @@ int check_assertion(policydb_t *p, avrule_t *avrule)
return rc;
}

static long int check_disjoint_attributes(sepol_handle_t *handle, const policydb_t *p)
{
const disjoint_attributes_rule_t *dattr;
unsigned long errors = 0;

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

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

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

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, "Disjoint Attributes Rule 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;
long 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 @@ -675,5 +707,15 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
if (errors)
ERR(handle, "%lu neverallow failures occurred", errors);

rc = check_disjoint_attributes(handle, p);
if (rc < 0) {
ERR(handle, "Error occurred while checking Disjoint Attributes Rules");
return -1;
}
if (rc) {
ERR(handle, "%ld Disjoint Attributes Rule 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 disjoint_attributes_copy(expand_state_t *state)
{
const disjoint_attributes_rule_t *old;
disjoint_attributes_rule_t *list = NULL;

for (old = state->base->disjoint_attributes; old; old = old->next) {
disjoint_attributes_rule_t *new;

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

disjoint_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->disjoint_attributes) {
disjoint_attributes_rule_t *d;
for (d = state->out->disjoint_attributes; d->next; d = d->next) {}
d->next = new;
} else
state->out->disjoint_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 @@ -3177,6 +3216,10 @@ int expand_module(sepol_handle_t * handle,
if (genfs_copy(&state))
goto cleanup;

/* copy disjoint attributes rules */
if (disjoint_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
32 changes: 32 additions & 0 deletions libsepol/src/kernel_to_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,33 @@ static int write_filename_trans_rules_to_conf(FILE *out, struct policydb *pdb)
return rc;
}

static int write_disjoint_attributes_to_conf(FILE *out, const struct policydb *pdb)
{
const disjoint_attributes_rule_t *dattr;

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

sepol_printf(out, "disjoint_attributes ");

ebitmap_for_each_positive_bit(&dattr->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;
}

static char *level_to_str(struct policydb *pdb, struct mls_level *level)
{
ebitmap_t *cats = &level->cat;
Expand Down Expand Up @@ -3223,6 +3250,11 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
}
write_filename_trans_rules_to_conf(out, pdb);

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

if (pdb->mls) {
rc = write_range_trans_rules_to_conf(out, pdb);
if (rc != 0) {
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_disjoint_attributes(link_state_t * state, const policy_module_t *module)
{
const disjoint_attributes_rule_t *dattr_rule;
disjoint_attributes_rule_t *list = NULL;

for (dattr_rule = module->policy->disjoint_attributes; dattr_rule; dattr_rule = dattr_rule->next) {
disjoint_attributes_rule_t *new_dattr;

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

disjoint_attributes_rule_init(new_dattr);

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

if (list)
list->next = new_dattr;
else {
if (state->base->disjoint_attributes) {
disjoint_attributes_rule_t *d;
for (d = state->base->disjoint_attributes; d->next; d = d->next) {}
d->next = new_dattr;
} else
state->base->disjoint_attributes = new_dattr;
}
list = new_dattr;
}

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_disjoint_attributes(state, module);
if (ret) {
return ret;
}

return 0;
}

Expand Down