Skip to content

Commit 054e921

Browse files
committed
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: SELinuxProject#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
1 parent e46d08f commit 054e921

File tree

8 files changed

+325
-16
lines changed

8 files changed

+325
-16
lines changed

libsepol/include/sepol/policydb/policydb.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ typedef struct type_datum {
192192
uint32_t bounds; /* bounds type, if exist */
193193
} type_datum_t;
194194

195+
/* Mutual exclusive attributes */
196+
typedef struct disjoint_attributes_rule {
197+
ebitmap_t attrs; /* mutual exclusive attributes */
198+
struct disjoint_attributes_rule *next;
199+
} disjoint_attributes_rule_t;
200+
195201
/*
196202
* Properties of type_datum
197203
* available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
@@ -606,6 +612,10 @@ typedef struct policydb {
606612
bitmaps. Someday the 0 bit may be used for global permissive */
607613
ebitmap_t permissive_map;
608614

615+
/* mutual exclusive attributes (not preserved in kernel policy).
616+
stored as linked list */
617+
disjoint_attributes_rule_t *disjoint_attributes;
618+
609619
unsigned policyvers;
610620

611621
unsigned handle_unknown;
@@ -697,6 +707,8 @@ extern void level_datum_init(level_datum_t * x);
697707
extern void level_datum_destroy(level_datum_t * x);
698708
extern void cat_datum_init(cat_datum_t * x);
699709
extern void cat_datum_destroy(cat_datum_t * x);
710+
extern void disjoint_attributes_rule_init(disjoint_attributes_rule_t * x);
711+
extern void disjoint_attributes_rule_destroy(disjoint_attributes_rule_t * x);
700712
extern int check_assertion(policydb_t *p, avrule_t *avrule);
701713
extern int check_assertions(sepol_handle_t * handle,
702714
policydb_t * p, avrule_t * avrules);
@@ -784,9 +796,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
784796
#define MOD_POLICYDB_VERSION_INFINIBAND 19
785797
#define MOD_POLICYDB_VERSION_GLBLUB 20
786798
#define MOD_POLICYDB_VERSION_SELF_TYPETRANS 21
799+
#define MOD_POLICYDB_VERSION_DISJOINT_ATTRIBUTES 22 /* disjoint attributes compile time constraint */
787800

788801
#define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
789-
#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_SELF_TYPETRANS
802+
#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_DISJOINT_ATTRIBUTES
790803

791804
#define POLICYDB_CONFIG_MLS 1
792805

libsepol/src/assertion.c

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct avtab_match_args {
3636
unsigned long errors;
3737
};
3838

39-
static const char* policy_name(policydb_t *p) {
39+
static const char* policy_name(const policydb_t *p) {
4040
const char *policy_file = "policy.conf";
4141
if (p->name) {
4242
policy_file = p->name;
@@ -146,7 +146,7 @@ static void extended_permissions_violated(avtab_extended_perms_t *result,
146146
}
147147

148148
/* Same scenarios of interest as check_assertion_extended_permissions */
149-
static int report_assertion_extended_permissions(sepol_handle_t *handle,
149+
static unsigned long report_assertion_extended_permissions(sepol_handle_t *handle,
150150
policydb_t *p, const avrule_t *avrule,
151151
unsigned int stype, unsigned int ttype,
152152
const class_perm_node_t *curperm, uint32_t perms,
@@ -162,7 +162,7 @@ static int report_assertion_extended_permissions(sepol_handle_t *handle,
162162
unsigned int i, j;
163163
int rc;
164164
int found_xperm = 0;
165-
int errors = 0;
165+
unsigned long errors = 0;
166166

167167
memcpy(&tmp_key, k, sizeof(avtab_key_t));
168168
tmp_key.specified = AVTAB_XPERMS_ALLOWED;
@@ -319,7 +319,7 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void
319319
return rc;
320320
}
321321

322-
static int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
322+
static long int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
323323
{
324324
int rc;
325325
struct avtab_match_args args;
@@ -640,20 +640,52 @@ int check_assertion(policydb_t *p, avrule_t *avrule)
640640
return rc;
641641
}
642642

643+
static long int check_disjoint_attributes(sepol_handle_t *handle, const policydb_t *p)
644+
{
645+
const disjoint_attributes_rule_t *dattr;
646+
unsigned long errors = 0;
647+
648+
for (dattr = p->disjoint_attributes; dattr; dattr = dattr->next) {
649+
ebitmap_node_t *first_node;
650+
unsigned int first_bit;
651+
652+
ebitmap_for_each_positive_bit(&dattr->attrs, first_node, first_bit) {
653+
ebitmap_node_t *second_node;
654+
unsigned int second_bit;
655+
656+
ebitmap_for_each_positive_bit_after(&dattr->attrs, second_node, second_bit, first_node, first_bit) {
657+
ebitmap_t attr_union;
658+
ebitmap_node_t *type_node;
659+
unsigned int type_bit;
660+
int rc;
661+
662+
rc = ebitmap_and(&attr_union, &p->attr_type_map[first_bit], &p->attr_type_map[second_bit]);
663+
if (rc < 0)
664+
return rc;
665+
666+
ebitmap_for_each_positive_bit(&attr_union, type_node, type_bit) {
667+
ERR(handle, "Disjoint Attributes Rule violation, type %s associated with attributes %s and %s",
668+
p->p_type_val_to_name[type_bit],
669+
p->p_type_val_to_name[first_bit],
670+
p->p_type_val_to_name[second_bit]);
671+
errors++;
672+
}
673+
674+
ebitmap_destroy(&attr_union);
675+
}
676+
}
677+
}
678+
679+
return errors;
680+
}
681+
643682
int check_assertions(sepol_handle_t * handle, policydb_t * p,
644683
avrule_t * avrules)
645684
{
646-
int rc;
685+
long int rc;
647686
avrule_t *a;
648687
unsigned long errors = 0;
649688

650-
if (!avrules) {
651-
/* Since assertions are stored in avrules, if it is NULL
652-
there won't be any to check. This also prevents an invalid
653-
free if the avtabs are never initialized */
654-
return 0;
655-
}
656-
657689
for (a = avrules; a != NULL; a = a->next) {
658690
if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
659691
continue;
@@ -675,5 +707,15 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
675707
if (errors)
676708
ERR(handle, "%lu neverallow failures occurred", errors);
677709

710+
rc = check_disjoint_attributes(handle, p);
711+
if (rc < 0) {
712+
ERR(handle, "Error occurred while checking Disjoint Attributes Rules");
713+
return -1;
714+
}
715+
if (rc) {
716+
ERR(handle, "%ld Disjoint Attributes Rule failures occurred", rc);
717+
errors += rc;
718+
}
719+
678720
return errors ? -1 : 0;
679721
}

libsepol/src/expand.c

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static void expand_state_init(expand_state_t * state)
5656
memset(state, 0, sizeof(expand_state_t));
5757
}
5858

59-
static int map_ebitmap(ebitmap_t * src, ebitmap_t * dst, uint32_t * map)
59+
static int map_ebitmap(const ebitmap_t * src, ebitmap_t * dst, const uint32_t * map)
6060
{
6161
unsigned int i;
6262
ebitmap_node_t *tnode;
@@ -2341,6 +2341,45 @@ static int genfs_copy(expand_state_t * state)
23412341
return 0;
23422342
}
23432343

2344+
static int disjoint_attributes_copy(expand_state_t *state)
2345+
{
2346+
const disjoint_attributes_rule_t *old;
2347+
disjoint_attributes_rule_t *list = NULL;
2348+
2349+
for (old = state->base->disjoint_attributes; old; old = old->next) {
2350+
disjoint_attributes_rule_t *new;
2351+
2352+
new = malloc(sizeof(disjoint_attributes_rule_t));
2353+
if (!new) {
2354+
ERR(state->handle, "Out of memory!");
2355+
return -1;
2356+
}
2357+
2358+
disjoint_attributes_rule_init(new);
2359+
2360+
if (map_ebitmap(&old->attrs, &new->attrs, state->typemap)) {
2361+
ERR(state->handle, "out of memory");
2362+
ebitmap_destroy(&new->attrs);
2363+
free(new);
2364+
return -1;
2365+
}
2366+
2367+
if (list)
2368+
list->next = new;
2369+
else {
2370+
if (state->out->disjoint_attributes) {
2371+
disjoint_attributes_rule_t *d;
2372+
for (d = state->out->disjoint_attributes; d->next; d = d->next) {}
2373+
d->next = new;
2374+
} else
2375+
state->out->disjoint_attributes = new;
2376+
}
2377+
list = new;
2378+
}
2379+
2380+
return 0;
2381+
}
2382+
23442383
static int type_attr_map(hashtab_key_t key
23452384
__attribute__ ((unused)), hashtab_datum_t datum,
23462385
void *ptr)
@@ -3177,6 +3216,10 @@ int expand_module(sepol_handle_t * handle,
31773216
if (genfs_copy(&state))
31783217
goto cleanup;
31793218

3219+
/* copy disjoint attributes rules */
3220+
if (disjoint_attributes_copy(&state))
3221+
goto cleanup;
3222+
31803223
/* Build the type<->attribute maps and remove attributes. */
31813224
state.out->attr_type_map = calloc(state.out->p_types.nprim,
31823225
sizeof(ebitmap_t));

libsepol/src/kernel_to_conf.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,33 @@ static int write_filename_trans_rules_to_conf(FILE *out, struct policydb *pdb)
19331933
return rc;
19341934
}
19351935

1936+
static int write_disjoint_attributes_to_conf(FILE *out, const struct policydb *pdb)
1937+
{
1938+
const disjoint_attributes_rule_t *dattr;
1939+
1940+
for (dattr = pdb->disjoint_attributes; dattr; dattr = dattr->next) {
1941+
struct ebitmap_node *node;
1942+
unsigned int bit;
1943+
int first = 1;
1944+
1945+
sepol_printf(out, "disjoint_attributes ");
1946+
1947+
ebitmap_for_each_positive_bit(&dattr->attrs, node, bit) {
1948+
if (first) {
1949+
first = 0;
1950+
} else {
1951+
sepol_printf(out, ", ");
1952+
}
1953+
1954+
sepol_printf(out, "%s", pdb->p_type_val_to_name[bit - 1]);
1955+
}
1956+
1957+
sepol_printf(out, ";\n");
1958+
}
1959+
1960+
return 0;
1961+
}
1962+
19361963
static char *level_to_str(struct policydb *pdb, struct mls_level *level)
19371964
{
19381965
ebitmap_t *cats = &level->cat;
@@ -3223,6 +3250,11 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
32233250
}
32243251
write_filename_trans_rules_to_conf(out, pdb);
32253252

3253+
rc = write_disjoint_attributes_to_conf(out, pdb);
3254+
if (rc != 0) {
3255+
goto exit;
3256+
}
3257+
32263258
if (pdb->mls) {
32273259
rc = write_range_trans_rules_to_conf(out, pdb);
32283260
if (rc != 0) {

libsepol/src/link.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,6 +1857,45 @@ static int scope_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
18571857
return -1;
18581858
}
18591859

1860+
static int copy_disjoint_attributes(link_state_t * state, const policy_module_t *module)
1861+
{
1862+
const disjoint_attributes_rule_t *dattr_rule;
1863+
disjoint_attributes_rule_t *list = NULL;
1864+
1865+
for (dattr_rule = module->policy->disjoint_attributes; dattr_rule; dattr_rule = dattr_rule->next) {
1866+
disjoint_attributes_rule_t *new_dattr;
1867+
1868+
new_dattr = malloc(sizeof(disjoint_attributes_rule_t));
1869+
if (!new_dattr) {
1870+
ERR(state->handle, "Out of memory!");
1871+
return -1;
1872+
}
1873+
1874+
disjoint_attributes_rule_init(new_dattr);
1875+
1876+
if (ebitmap_convert(&dattr_rule->attrs, &new_dattr->attrs, module->map[SYM_TYPES])) {
1877+
ebitmap_destroy(&new_dattr->attrs);
1878+
free(new_dattr);
1879+
ERR(state->handle, "Out of memory!");
1880+
return -1;
1881+
}
1882+
1883+
if (list)
1884+
list->next = new_dattr;
1885+
else {
1886+
if (state->base->disjoint_attributes) {
1887+
disjoint_attributes_rule_t *d;
1888+
for (d = state->base->disjoint_attributes; d->next; d = d->next) {}
1889+
d->next = new_dattr;
1890+
} else
1891+
state->base->disjoint_attributes = new_dattr;
1892+
}
1893+
list = new_dattr;
1894+
}
1895+
1896+
return 0;
1897+
}
1898+
18601899
/* Copy a module over to a base, remapping all values within. After
18611900
* all identifiers and rules are done, copy the scoping information.
18621901
* This is when it checks for duplicate declarations. */
@@ -1891,6 +1930,11 @@ static int copy_module(link_state_t * state, policy_module_t * module)
18911930
}
18921931
}
18931932

1933+
ret = copy_disjoint_attributes(state, module);
1934+
if (ret) {
1935+
return ret;
1936+
}
1937+
18941938
return 0;
18951939
}
18961940

0 commit comments

Comments
 (0)