1790 lines
53 KiB
Diff
1790 lines
53 KiB
Diff
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
|
|
index f53a499..0165eed 100644
|
|
--- a/libsepol/include/sepol/policydb/policydb.h
|
|
+++ b/libsepol/include/sepol/policydb/policydb.h
|
|
@@ -116,6 +116,7 @@ typedef struct class_datum {
|
|
#define DEFAULT_TARGET 2
|
|
char default_user;
|
|
char default_role;
|
|
+ char default_type;
|
|
/* Options how a new object range should be decided */
|
|
#define DEFAULT_SOURCE_LOW 1
|
|
#define DEFAULT_SOURCE_HIGH 2
|
|
@@ -681,10 +682,12 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
|
|
#define POLICYDB_VERSION_FILENAME_TRANS 25
|
|
#define POLICYDB_VERSION_ROLETRANS 26
|
|
#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
|
|
+#define POLICYDB_VERSION_DEFAULT_TYPE 28
|
|
+#define POLICYDB_VERSION_CONSTRAINT_NAMES 29
|
|
|
|
/* Range of policy versions we understand*/
|
|
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
|
|
-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_NEW_OBJECT_DEFAULTS
|
|
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES
|
|
|
|
/* Module versions and specific changes*/
|
|
#define MOD_POLICYDB_VERSION_BASE 4
|
|
@@ -701,9 +704,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
|
|
#define MOD_POLICYDB_VERSION_ROLEATTRIB 13
|
|
#define MOD_POLICYDB_VERSION_TUNABLE_SEP 14
|
|
#define MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 15
|
|
+#define MOD_POLICYDB_VERSION_DEFAULT_TYPE 16
|
|
+#define MOD_POLICYDB_VERSION_CONSTRAINT_NAMES 17
|
|
|
|
#define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
|
|
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS
|
|
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_CONSTRAINT_NAMES
|
|
|
|
#define POLICYDB_CONFIG_MLS 1
|
|
|
|
diff --git a/libsepol/include/sepol/policydb/services.h b/libsepol/include/sepol/policydb/services.h
|
|
index aef0c7b..1969a10 100644
|
|
--- a/libsepol/include/sepol/policydb/services.h
|
|
+++ b/libsepol/include/sepol/policydb/services.h
|
|
@@ -58,6 +58,38 @@ extern int sepol_compute_av_reason(sepol_security_id_t ssid,
|
|
struct sepol_av_decision *avd,
|
|
unsigned int *reason);
|
|
|
|
+/*
|
|
+ * Same as above, but also returns the constraint expression calculations
|
|
+ * whether allowed or denied in a buffer. This buffer is allocated by
|
|
+ * this call and must be free'd by the caller using free(3). The contraint
|
|
+ * buffer will contain any constraints in infix notation.
|
|
+ * If the SHOW_GRANTED flag is set it will show granted and denied
|
|
+ * constraints. The default is to show only denied constraints.
|
|
+ */
|
|
+#define SHOW_GRANTED 1
|
|
+extern int sepol_compute_av_reason_buffer(sepol_security_id_t ssid,
|
|
+ sepol_security_id_t tsid,
|
|
+ sepol_security_class_t tclass,
|
|
+ sepol_access_vector_t requested,
|
|
+ struct sepol_av_decision *avd,
|
|
+ unsigned int *reason,
|
|
+ char **reason_buf,
|
|
+ unsigned int flags);
|
|
+/*
|
|
+ * Return a class ID associated with the class string representation
|
|
+ * specified by `class_name'.
|
|
+ */
|
|
+extern int sepol_class_name_to_id(const char *class_name,
|
|
+ sepol_security_class_t *tclass);
|
|
+
|
|
+/*
|
|
+ * Return a permission av bit associated with tclass and the string
|
|
+ * representation of the `perm_name'.
|
|
+ */
|
|
+extern int sepol_perm_name_to_av(sepol_security_class_t tclass,
|
|
+ const char *perm_name,
|
|
+ sepol_access_vector_t *av);
|
|
+
|
|
/*
|
|
* Compute a SID to use for labeling a new object in the
|
|
* class `tclass' based on a SID pair.
|
|
diff --git a/libsepol/src/avrule_block.c b/libsepol/src/avrule_block.c
|
|
index 16c89f3..84cfaf8 100644
|
|
--- a/libsepol/src/avrule_block.c
|
|
+++ b/libsepol/src/avrule_block.c
|
|
@@ -61,7 +61,6 @@ avrule_decl_t *avrule_decl_create(uint32_t decl_id)
|
|
for (i = 0; i < SYM_NUM; i++) {
|
|
if (symtab_init(&decl->symtab[i], symtab_sizes[i])) {
|
|
avrule_decl_destroy(decl);
|
|
- free(decl);
|
|
return NULL;
|
|
}
|
|
}
|
|
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
|
|
index 2003eb6..34e764b 100644
|
|
--- a/libsepol/src/expand.c
|
|
+++ b/libsepol/src/expand.c
|
|
@@ -49,6 +49,82 @@ typedef struct expand_state {
|
|
int expand_neverallow;
|
|
} expand_state_t;
|
|
|
|
+struct linear_probe {
|
|
+ filename_trans_t **table; /* filename_trans chunks with same stype */
|
|
+ filename_trans_t **ends; /* pointers to ends of **table chunks */
|
|
+ uint32_t length; /* length of the table */
|
|
+};
|
|
+
|
|
+static int linear_probe_create(struct linear_probe *probe, uint32_t length)
|
|
+{
|
|
+ probe->table = calloc(length, sizeof(*probe->table));
|
|
+ if (probe->table == NULL)
|
|
+ return -1;
|
|
+
|
|
+ probe->ends = calloc(length, sizeof(*probe->ends));
|
|
+ if (probe->ends == NULL)
|
|
+ return -1;
|
|
+
|
|
+ probe->length = length;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void linear_probe_destroy(struct linear_probe *probe)
|
|
+{
|
|
+ if (probe->length == 0)
|
|
+ return;
|
|
+
|
|
+ free(probe->table);
|
|
+ free(probe->ends);
|
|
+ memset(probe, 0, sizeof(*probe));
|
|
+}
|
|
+
|
|
+static void linear_probe_insert(struct linear_probe *probe, uint32_t key,
|
|
+ filename_trans_t *data)
|
|
+{
|
|
+ assert(probe->length > key);
|
|
+
|
|
+ if (probe->table[key] != NULL) {
|
|
+ data->next = probe->table[key];
|
|
+ probe->table[key] = data;
|
|
+ } else {
|
|
+ probe->table[key] = probe->ends[key] = data;
|
|
+ }
|
|
+}
|
|
+
|
|
+static filename_trans_t *linear_probe_find(struct linear_probe *probe, uint32_t key)
|
|
+{
|
|
+ assert(probe->length > key);
|
|
+
|
|
+ return probe->table[key];
|
|
+}
|
|
+
|
|
+/* Returns all chunks stored in the *probe as single-linked list */
|
|
+static filename_trans_t *linear_probe_dump(struct linear_probe *probe,
|
|
+ filename_trans_t **endp)
|
|
+{
|
|
+ uint32_t i;
|
|
+ filename_trans_t *result = NULL;
|
|
+ filename_trans_t *end = NULL;
|
|
+
|
|
+ for (i = 0; i < probe->length; i++) {
|
|
+ if (probe->table[i] != NULL) {
|
|
+ if (end == NULL)
|
|
+ end = probe->ends[i];
|
|
+ probe->ends[i]->next = result;
|
|
+ result = probe->table[i];
|
|
+ probe->table[i] = probe->ends[i] = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Incoherent result and end pointers indicates bug */
|
|
+ assert((result != NULL && end != NULL) || (result == NULL && end == NULL));
|
|
+
|
|
+ *endp = end;
|
|
+ return result;
|
|
+}
|
|
+
|
|
static void expand_state_init(expand_state_t * state)
|
|
{
|
|
memset(state, 0, sizeof(expand_state_t));
|
|
@@ -306,6 +382,16 @@ static int constraint_node_clone(constraint_node_t ** dst,
|
|
new_expr->op = expr->op;
|
|
if (new_expr->expr_type == CEXPR_NAMES) {
|
|
if (new_expr->attr & CEXPR_TYPE) {
|
|
+ /*
|
|
+ * Copy over constraint policy source types and/or
|
|
+ * attributes for sepol_compute_av_reason_buffer(3) so that
|
|
+ * utilities can analyse constraint errors.
|
|
+ */
|
|
+ if (map_ebitmap(&expr->type_names->types,
|
|
+ &new_expr->type_names->types, state->typemap)) {
|
|
+ ERR(NULL, "Failed to map type_names->types");
|
|
+ goto out_of_mem;
|
|
+ }
|
|
/* Type sets require expansion and conversion. */
|
|
if (expand_convert_type_set(state->out,
|
|
state->
|
|
@@ -377,6 +463,13 @@ static int class_copy_default_new_object(expand_state_t *state,
|
|
}
|
|
newdatum->default_role = olddatum->default_role;
|
|
}
|
|
+ if (olddatum->default_type) {
|
|
+ if (newdatum->default_type && olddatum->default_type != newdatum->default_type) {
|
|
+ ERR(state->handle, "Found conflicting default type definitions");
|
|
+ return SEPOL_ENOTSUP;
|
|
+ }
|
|
+ newdatum->default_type = olddatum->default_type;
|
|
+ }
|
|
if (olddatum->default_range) {
|
|
if (newdatum->default_range && olddatum->default_range != newdatum->default_range) {
|
|
ERR(state->handle, "Found conflicting default range definitions");
|
|
@@ -812,6 +905,7 @@ static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
|
|
new_id = strdup(id);
|
|
if (!new_id) {
|
|
ERR(state->handle, "Out of memory!");
|
|
+ free(new_role);
|
|
return -1;
|
|
}
|
|
|
|
@@ -877,9 +971,13 @@ int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l,
|
|
|
|
l->sens = sl->sens;
|
|
levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
|
|
- p->p_sens_val_to_name[l->
|
|
- sens -
|
|
- 1]);
|
|
+ p->p_sens_val_to_name[l->sens - 1]);
|
|
+ if (!levdatum) {
|
|
+ ERR(h, "%s: Impossible situation found, nothing in p_levels.table.\n",
|
|
+ __func__);
|
|
+ errno = ENOENT;
|
|
+ return -1;
|
|
+ }
|
|
for (cat = sl->cat; cat; cat = cat->next) {
|
|
if (cat->low > cat->high) {
|
|
ERR(h, "Category range is not valid %s.%s",
|
|
@@ -963,6 +1061,7 @@ static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
|
|
new_id = strdup(id);
|
|
if (!new_id) {
|
|
ERR(state->handle, "Out of memory!");
|
|
+ free(new_user);
|
|
return -1;
|
|
}
|
|
ret = hashtab_insert(state->out->p_users.table,
|
|
@@ -1357,10 +1456,20 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules)
|
|
static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules)
|
|
{
|
|
unsigned int i, j;
|
|
- filename_trans_t *new_trans, *cur_trans;
|
|
+ filename_trans_t *new_trans, *cur_trans, *end;
|
|
filename_trans_rule_t *cur_rule;
|
|
ebitmap_t stypes, ttypes;
|
|
ebitmap_node_t *snode, *tnode;
|
|
+ struct linear_probe probe;
|
|
+
|
|
+ /*
|
|
+ * Linear probing speeds-up finding filename_trans rules with certain
|
|
+ * "stype" value.
|
|
+ */
|
|
+ if (linear_probe_create(&probe, 4096)) { /* Assume 4096 is enough for most cases */
|
|
+ ERR(state->handle, "Out of memory!");
|
|
+ return -1;
|
|
+ }
|
|
|
|
cur_rule = rules;
|
|
while (cur_rule) {
|
|
@@ -1383,6 +1492,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r
|
|
|
|
mapped_otype = state->typemap[cur_rule->otype - 1];
|
|
|
|
+ if (ebitmap_length(&stypes) > probe.length) {
|
|
+ linear_probe_destroy(&probe);
|
|
+ if (linear_probe_create(&probe, ebitmap_length(&stypes))) {
|
|
+ ERR(state->handle, "Out of memory!");
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
ebitmap_for_each_bit(&stypes, snode, i) {
|
|
if (!ebitmap_node_get_bit(snode, i))
|
|
continue;
|
|
@@ -1390,16 +1507,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r
|
|
if (!ebitmap_node_get_bit(tnode, j))
|
|
continue;
|
|
|
|
- cur_trans = state->out->filename_trans;
|
|
- while (cur_trans) {
|
|
- if ((cur_trans->stype == i + 1) &&
|
|
- (cur_trans->ttype == j + 1) &&
|
|
+ cur_trans = linear_probe_find(&probe, i);
|
|
+ while (cur_trans != NULL) {
|
|
+ if ((cur_trans->ttype == j + 1) &&
|
|
(cur_trans->tclass == cur_rule->tclass) &&
|
|
(!strcmp(cur_trans->name, cur_rule->name))) {
|
|
/* duplicate rule, who cares */
|
|
if (cur_trans->otype == mapped_otype)
|
|
break;
|
|
-
|
|
ERR(state->handle, "Conflicting filename trans rules %s %s %s : %s otype1:%s otype2:%s",
|
|
cur_trans->name,
|
|
state->out->p_type_val_to_name[i],
|
|
@@ -1407,7 +1522,7 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r
|
|
state->out->p_class_val_to_name[cur_trans->tclass - 1],
|
|
state->out->p_type_val_to_name[cur_trans->otype - 1],
|
|
state->out->p_type_val_to_name[mapped_otype - 1]);
|
|
-
|
|
+
|
|
return -1;
|
|
}
|
|
cur_trans = cur_trans->next;
|
|
@@ -1422,8 +1537,6 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r
|
|
return -1;
|
|
}
|
|
memset(new_trans, 0, sizeof(*new_trans));
|
|
- new_trans->next = state->out->filename_trans;
|
|
- state->out->filename_trans = new_trans;
|
|
|
|
new_trans->name = strdup(cur_rule->name);
|
|
if (!new_trans->name) {
|
|
@@ -1434,9 +1547,16 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r
|
|
new_trans->ttype = j + 1;
|
|
new_trans->tclass = cur_rule->tclass;
|
|
new_trans->otype = mapped_otype;
|
|
+ linear_probe_insert(&probe, i, new_trans);
|
|
}
|
|
}
|
|
|
|
+ cur_trans = linear_probe_dump(&probe, &end);
|
|
+ if (cur_trans != NULL) {
|
|
+ end->next = state->out->filename_trans;
|
|
+ state->out->filename_trans = cur_trans;
|
|
+ }
|
|
+
|
|
ebitmap_destroy(&stypes);
|
|
ebitmap_destroy(&ttypes);
|
|
|
|
@@ -1981,6 +2101,8 @@ static int cond_node_copy(expand_state_t * state, cond_node_t * cn)
|
|
}
|
|
|
|
if (cond_node_map_bools(state, tmp)) {
|
|
+ cond_node_destroy(tmp);
|
|
+ free(tmp);
|
|
ERR(state->handle, "Error mapping booleans");
|
|
return -1;
|
|
}
|
|
@@ -2037,14 +2159,13 @@ static int ocontext_copy_xen(expand_state_t *state)
|
|
else
|
|
state->out->ocontexts[i] = n;
|
|
l = n;
|
|
+ if (context_copy(&n->context[0], &c->context[0],
|
|
+ state)) {
|
|
+ ERR(state->handle, "Out of memory!");
|
|
+ return -1;
|
|
+ }
|
|
switch (i) {
|
|
case OCON_XEN_ISID:
|
|
- if (c->context[0].user == 0) {
|
|
- ERR(state->handle,
|
|
- "Missing context for %s initial sid",
|
|
- c->u.name);
|
|
- return -1;
|
|
- }
|
|
n->sid[0] = c->sid[0];
|
|
break;
|
|
case OCON_XEN_PIRQ:
|
|
@@ -2067,11 +2188,6 @@ static int ocontext_copy_xen(expand_state_t *state)
|
|
ERR(state->handle, "Unknown ocontext");
|
|
return -1;
|
|
}
|
|
- if (context_copy(&n->context[0], &c->context[0],
|
|
- state)) {
|
|
- ERR(state->handle, "Out of memory!");
|
|
- return -1;
|
|
- }
|
|
}
|
|
}
|
|
return 0;
|
|
@@ -2096,14 +2212,12 @@ static int ocontext_copy_selinux(expand_state_t *state)
|
|
else
|
|
state->out->ocontexts[i] = n;
|
|
l = n;
|
|
+ if (context_copy(&n->context[0], &c->context[0], state)) {
|
|
+ ERR(state->handle, "Out of memory!");
|
|
+ return -1;
|
|
+ }
|
|
switch (i) {
|
|
case OCON_ISID:
|
|
- if (c->context[0].user == 0) {
|
|
- ERR(state->handle,
|
|
- "Missing context for %s initial sid",
|
|
- c->u.name);
|
|
- return -1;
|
|
- }
|
|
n->sid[0] = c->sid[0];
|
|
break;
|
|
case OCON_FS: /* FALLTHROUGH */
|
|
@@ -2147,10 +2261,6 @@ static int ocontext_copy_selinux(expand_state_t *state)
|
|
ERR(state->handle, "Unknown ocontext");
|
|
return -1;
|
|
}
|
|
- if (context_copy(&n->context[0], &c->context[0], state)) {
|
|
- ERR(state->handle, "Out of memory!");
|
|
- return -1;
|
|
- }
|
|
}
|
|
}
|
|
return 0;
|
|
@@ -2188,9 +2298,15 @@ static int genfs_copy(expand_state_t * state)
|
|
memset(newgenfs, 0, sizeof(genfs_t));
|
|
newgenfs->fstype = strdup(genfs->fstype);
|
|
if (!newgenfs->fstype) {
|
|
+ free(newgenfs);
|
|
ERR(state->handle, "Out of memory!");
|
|
return -1;
|
|
}
|
|
+ if (!end)
|
|
+ state->out->genfs = newgenfs;
|
|
+ else
|
|
+ end->next = newgenfs;
|
|
+ end = newgenfs;
|
|
|
|
l = NULL;
|
|
for (c = genfs->head; c; c = c->next) {
|
|
@@ -2203,6 +2319,7 @@ static int genfs_copy(expand_state_t * state)
|
|
newc->u.name = strdup(c->u.name);
|
|
if (!newc->u.name) {
|
|
ERR(state->handle, "Out of memory!");
|
|
+ free(newc);
|
|
return -1;
|
|
}
|
|
newc->v.sclass = c->v.sclass;
|
|
@@ -2213,12 +2330,6 @@ static int genfs_copy(expand_state_t * state)
|
|
newgenfs->head = newc;
|
|
l = newc;
|
|
}
|
|
- if (!end) {
|
|
- state->out->genfs = newgenfs;
|
|
- } else {
|
|
- end->next = newgenfs;
|
|
- }
|
|
- end = newgenfs;
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -3009,7 +3120,8 @@ int expand_module(sepol_handle_t * handle,
|
|
}
|
|
|
|
cond_optimize_lists(state.out->cond_list);
|
|
- evaluate_conds(state.out);
|
|
+ if (evaluate_conds(state.out))
|
|
+ goto cleanup;
|
|
|
|
/* copy ocontexts */
|
|
if (ocontext_copy(&state, out->target_platform))
|
|
diff --git a/libsepol/src/genbools.c b/libsepol/src/genbools.c
|
|
index 612ff9a..6a06ec9 100644
|
|
--- a/libsepol/src/genbools.c
|
|
+++ b/libsepol/src/genbools.c
|
|
@@ -33,7 +33,7 @@ static char *strtrim(char *dest, char *source, int size)
|
|
static int process_boolean(char *buffer, char *name, int namesize, int *val)
|
|
{
|
|
char name1[BUFSIZ];
|
|
- char *ptr;
|
|
+ char *ptr = NULL;
|
|
char *tok = strtok_r(buffer, "=", &ptr);
|
|
if (tok) {
|
|
strncpy(name1, tok, BUFSIZ - 1);
|
|
diff --git a/libsepol/src/genusers.c b/libsepol/src/genusers.c
|
|
index 37528e2..7826b71 100644
|
|
--- a/libsepol/src/genusers.c
|
|
+++ b/libsepol/src/genusers.c
|
|
@@ -92,22 +92,32 @@ static int load_users(struct policydb *policydb, const char *path)
|
|
} else {
|
|
char *id = strdup(q);
|
|
|
|
+ if (!id) {
|
|
+ ERR(NULL, "out of memory");
|
|
+ free(buffer);
|
|
+ fclose(fp);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
/* Adding a new user definition. */
|
|
- usrdatum =
|
|
- (user_datum_t *) malloc(sizeof(user_datum_t));
|
|
- if (!id || !usrdatum) {
|
|
+ usrdatum = malloc(sizeof(user_datum_t));
|
|
+ if (!usrdatum) {
|
|
ERR(NULL, "out of memory");
|
|
free(buffer);
|
|
+ free(id);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
- memset(usrdatum, 0, sizeof(user_datum_t));
|
|
+
|
|
+ user_datum_init(usrdatum);
|
|
usrdatum->s.value = ++policydb->p_users.nprim;
|
|
- ebitmap_init(&usrdatum->roles.roles);
|
|
if (hashtab_insert(policydb->p_users.table,
|
|
id, (hashtab_datum_t) usrdatum)) {
|
|
ERR(NULL, "out of memory");
|
|
free(buffer);
|
|
+ free(id);
|
|
+ user_datum_destroy(usrdatum);
|
|
+ free(usrdatum);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
diff --git a/libsepol/src/link.c b/libsepol/src/link.c
|
|
index 01d3231..31b955c 100644
|
|
--- a/libsepol/src/link.c
|
|
+++ b/libsepol/src/link.c
|
|
@@ -223,6 +223,13 @@ static int class_copy_default_new_object(link_state_t *state,
|
|
}
|
|
newdatum->default_role = olddatum->default_role;
|
|
}
|
|
+ if (olddatum->default_type) {
|
|
+ if (newdatum->default_type && olddatum->default_type != newdatum->default_type) {
|
|
+ ERR(state->handle, "Found conflicting default type definitions");
|
|
+ return SEPOL_ENOTSUP;
|
|
+ }
|
|
+ newdatum->default_type = olddatum->default_type;
|
|
+ }
|
|
if (olddatum->default_range) {
|
|
if (newdatum->default_range && olddatum->default_range != newdatum->default_range) {
|
|
ERR(state->handle, "Found conflicting default range definitions");
|
|
@@ -676,13 +683,17 @@ static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
|
|
"%s: Modules may not declare new sensitivities.",
|
|
state->cur_mod_name);
|
|
return SEPOL_ENOTSUP;
|
|
- }
|
|
- if (scope->scope == SCOPE_REQ) {
|
|
+ } else if (scope->scope == SCOPE_REQ) {
|
|
/* unmet requirement */
|
|
ERR(state->handle,
|
|
"%s: Sensitivity %s not declared by base.",
|
|
state->cur_mod_name, id);
|
|
return SEPOL_ENOTSUP;
|
|
+ } else {
|
|
+ ERR(state->handle,
|
|
+ "%s: has an unknown scope: %d\n",
|
|
+ state->cur_mod_name, scope->scope);
|
|
+ return SEPOL_ENOTSUP;
|
|
}
|
|
}
|
|
|
|
@@ -704,8 +715,7 @@ static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
|
|
|
|
base_cat = hashtab_search(state->base->p_cats.table, id);
|
|
if (!base_cat) {
|
|
- scope =
|
|
- hashtab_search(state->cur->policy->p_cat_scope.table, id);
|
|
+ scope = hashtab_search(state->cur->policy->p_cat_scope.table, id);
|
|
if (!scope)
|
|
return SEPOL_ERR;
|
|
if (scope->scope == SCOPE_DECL) {
|
|
@@ -714,13 +724,18 @@ static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
|
|
"%s: Modules may not declare new categories.",
|
|
state->cur_mod_name);
|
|
return SEPOL_ENOTSUP;
|
|
- }
|
|
- if (scope->scope == SCOPE_REQ) {
|
|
+ } else if (scope->scope == SCOPE_REQ) {
|
|
/* unmet requirement */
|
|
ERR(state->handle,
|
|
"%s: Category %s not declared by base.",
|
|
state->cur_mod_name, id);
|
|
return SEPOL_ENOTSUP;
|
|
+ } else {
|
|
+ /* unknown scope? malformed policy? */
|
|
+ ERR(state->handle,
|
|
+ "%s: has an unknown scope: %d\n",
|
|
+ state->cur_mod_name, scope->scope);
|
|
+ return SEPOL_ENOTSUP;
|
|
}
|
|
}
|
|
|
|
@@ -2001,6 +2016,7 @@ static int is_decl_requires_met(link_state_t * state,
|
|
struct find_perm_arg fparg;
|
|
class_datum_t *cladatum;
|
|
uint32_t perm_value = j + 1;
|
|
+ int rc;
|
|
scope_datum_t *scope;
|
|
|
|
if (!ebitmap_node_get_bit(node, j)) {
|
|
@@ -2022,11 +2038,13 @@ static int is_decl_requires_met(link_state_t * state,
|
|
fparg.valuep = perm_value;
|
|
fparg.key = NULL;
|
|
|
|
- hashtab_map(cladatum->permissions.table, find_perm,
|
|
+ (void)hashtab_map(cladatum->permissions.table, find_perm,
|
|
&fparg);
|
|
- if (fparg.key == NULL && cladatum->comdatum != NULL)
|
|
- hashtab_map(cladatum->comdatum->permissions.
|
|
- table, find_perm, &fparg);
|
|
+ if (fparg.key == NULL && cladatum->comdatum != NULL) {
|
|
+ rc = hashtab_map(cladatum->comdatum->permissions.table,
|
|
+ find_perm, &fparg);
|
|
+ assert(rc == 1);
|
|
+ }
|
|
perm_id = fparg.key;
|
|
|
|
assert(perm_id != NULL);
|
|
@@ -2050,6 +2068,7 @@ static int debug_requirements(link_state_t * state, policydb_t * p)
|
|
int ret;
|
|
avrule_block_t *cur;
|
|
missing_requirement_t req;
|
|
+ memset(&req, 0, sizeof(req));
|
|
|
|
for (cur = p->global; cur != NULL; cur = cur->next) {
|
|
if (cur->enabled != NULL)
|
|
@@ -2062,34 +2081,27 @@ static int debug_requirements(link_state_t * state, policydb_t * p)
|
|
char *mod_name = cur->branch_list->module_name ?
|
|
cur->branch_list->module_name : "BASE";
|
|
if (req.symbol_type == SYM_CLASSES) {
|
|
-
|
|
struct find_perm_arg fparg;
|
|
|
|
class_datum_t *cladatum;
|
|
- cladatum =
|
|
- p->class_val_to_struct[req.symbol_value -
|
|
- 1];
|
|
+ cladatum = p->class_val_to_struct[req.symbol_value - 1];
|
|
|
|
fparg.valuep = req.perm_value;
|
|
fparg.key = NULL;
|
|
- hashtab_map(cladatum->permissions.table,
|
|
- find_perm, &fparg);
|
|
+ (void)hashtab_map(cladatum->permissions.table,
|
|
+ find_perm, &fparg);
|
|
|
|
if (cur->flags & AVRULE_OPTIONAL) {
|
|
ERR(state->handle,
|
|
"%s[%d]'s optional requirements were not met: class %s, permission %s",
|
|
mod_name, cur->branch_list->decl_id,
|
|
- p->p_class_val_to_name[req.
|
|
- symbol_value
|
|
- - 1],
|
|
+ p->p_class_val_to_name[req.symbol_value - 1],
|
|
fparg.key);
|
|
} else {
|
|
ERR(state->handle,
|
|
"%s[%d]'s global requirements were not met: class %s, permission %s",
|
|
mod_name, cur->branch_list->decl_id,
|
|
- p->p_class_val_to_name[req.
|
|
- symbol_value
|
|
- - 1],
|
|
+ p->p_class_val_to_name[req.symbol_value - 1],
|
|
fparg.key);
|
|
}
|
|
} else {
|
|
@@ -2137,7 +2149,7 @@ static void print_missing_requirements(link_state_t * state,
|
|
|
|
fparg.valuep = req->perm_value;
|
|
fparg.key = NULL;
|
|
- hashtab_map(cladatum->permissions.table, find_perm, &fparg);
|
|
+ (void)hashtab_map(cladatum->permissions.table, find_perm, &fparg);
|
|
|
|
ERR(state->handle,
|
|
"%s's global requirements were not met: class %s, permission %s",
|
|
@@ -2148,8 +2160,7 @@ static void print_missing_requirements(link_state_t * state,
|
|
"%s's global requirements were not met: %s %s",
|
|
mod_name,
|
|
symtab_names[req->symbol_type],
|
|
- p->sym_val_to_name[req->symbol_type][req->symbol_value -
|
|
- 1]);
|
|
+ p->sym_val_to_name[req->symbol_type][req->symbol_value - 1]);
|
|
}
|
|
}
|
|
|
|
diff --git a/libsepol/src/module.c b/libsepol/src/module.c
|
|
index b5b807e..1665ede 100644
|
|
--- a/libsepol/src/module.c
|
|
+++ b/libsepol/src/module.c
|
|
@@ -59,21 +59,34 @@ static int policy_file_seek(struct policy_file *fp, size_t offset)
|
|
}
|
|
}
|
|
|
|
-static size_t policy_file_length(struct policy_file *fp)
|
|
+static int policy_file_length(struct policy_file *fp, size_t *out)
|
|
{
|
|
long prev_offset, end_offset;
|
|
+ int rc;
|
|
switch (fp->type) {
|
|
case PF_USE_STDIO:
|
|
prev_offset = ftell(fp->fp);
|
|
- fseek(fp->fp, 0L, SEEK_END);
|
|
+ if (prev_offset < 0)
|
|
+ return prev_offset;
|
|
+ rc = fseek(fp->fp, 0L, SEEK_END);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
end_offset = ftell(fp->fp);
|
|
- fseek(fp->fp, prev_offset, SEEK_SET);
|
|
- return end_offset;
|
|
+ if (end_offset < 0)
|
|
+ return end_offset;
|
|
+ rc = fseek(fp->fp, prev_offset, SEEK_SET);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+ *out = end_offset;
|
|
+ break;
|
|
case PF_USE_MEMORY:
|
|
- return fp->size;
|
|
+ *out = fp->size;
|
|
+ break;;
|
|
default:
|
|
- return 0;
|
|
+ *out = 0;
|
|
+ break;
|
|
}
|
|
+ return 0;
|
|
}
|
|
|
|
static int module_package_init(sepol_module_package_t * p)
|
|
@@ -103,10 +116,17 @@ static int set_char(char **field, char *data, size_t len)
|
|
|
|
int sepol_module_package_create(sepol_module_package_t ** p)
|
|
{
|
|
+ int rc;
|
|
+
|
|
*p = calloc(1, sizeof(sepol_module_package_t));
|
|
if (!(*p))
|
|
return -1;
|
|
- return module_package_init(*p);
|
|
+
|
|
+ rc = module_package_init(*p);
|
|
+ if (rc < 0)
|
|
+ free(*p);
|
|
+
|
|
+ return rc;
|
|
}
|
|
|
|
hidden_def(sepol_module_package_create)
|
|
@@ -413,7 +433,10 @@ static int module_package_read_offsets(sepol_module_package_t * mod,
|
|
}
|
|
}
|
|
|
|
- off[nsec] = policy_file_length(file);
|
|
+ rc = policy_file_length(file, &off[nsec]);
|
|
+ if (rc < 0)
|
|
+ goto err;
|
|
+
|
|
if (nsec && off[nsec] < off[nsec-1]) {
|
|
ERR(file->handle, "offset greater than file size (at %u, "
|
|
"offset %zu -> %zu", nsec, off[nsec - 1],
|
|
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
|
|
index ff292f6..ef0252a 100644
|
|
--- a/libsepol/src/policydb.c
|
|
+++ b/libsepol/src/policydb.c
|
|
@@ -158,6 +158,20 @@ static struct policydb_compat_info policydb_compat[] = {
|
|
.target_platform = SEPOL_TARGET_SELINUX,
|
|
},
|
|
{
|
|
+ .type = POLICY_KERN,
|
|
+ .version = POLICYDB_VERSION_DEFAULT_TYPE,
|
|
+ .sym_num = SYM_NUM,
|
|
+ .ocon_num = OCON_NODE6 + 1,
|
|
+ .target_platform = SEPOL_TARGET_SELINUX,
|
|
+ },
|
|
+ {
|
|
+ .type = POLICY_KERN,
|
|
+ .version = POLICYDB_VERSION_CONSTRAINT_NAMES,
|
|
+ .sym_num = SYM_NUM,
|
|
+ .ocon_num = OCON_NODE6 + 1,
|
|
+ .target_platform = SEPOL_TARGET_SELINUX,
|
|
+ },
|
|
+ {
|
|
.type = POLICY_BASE,
|
|
.version = MOD_POLICYDB_VERSION_BASE,
|
|
.sym_num = SYM_NUM,
|
|
@@ -242,6 +256,20 @@ static struct policydb_compat_info policydb_compat[] = {
|
|
.target_platform = SEPOL_TARGET_SELINUX,
|
|
},
|
|
{
|
|
+ .type = POLICY_BASE,
|
|
+ .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE,
|
|
+ .sym_num = SYM_NUM,
|
|
+ .ocon_num = OCON_NODE6 + 1,
|
|
+ .target_platform = SEPOL_TARGET_SELINUX,
|
|
+ },
|
|
+ {
|
|
+ .type = POLICY_BASE,
|
|
+ .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES,
|
|
+ .sym_num = SYM_NUM,
|
|
+ .ocon_num = OCON_NODE6 + 1,
|
|
+ .target_platform = SEPOL_TARGET_SELINUX,
|
|
+ },
|
|
+ {
|
|
.type = POLICY_MOD,
|
|
.version = MOD_POLICYDB_VERSION_BASE,
|
|
.sym_num = SYM_NUM,
|
|
@@ -325,6 +353,20 @@ static struct policydb_compat_info policydb_compat[] = {
|
|
.ocon_num = 0,
|
|
.target_platform = SEPOL_TARGET_SELINUX,
|
|
},
|
|
+ {
|
|
+ .type = POLICY_MOD,
|
|
+ .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE,
|
|
+ .sym_num = SYM_NUM,
|
|
+ .ocon_num = 0,
|
|
+ .target_platform = SEPOL_TARGET_SELINUX,
|
|
+ },
|
|
+ {
|
|
+ .type = POLICY_MOD,
|
|
+ .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES,
|
|
+ .sym_num = SYM_NUM,
|
|
+ .ocon_num = 0,
|
|
+ .target_platform = SEPOL_TARGET_SELINUX,
|
|
+ },
|
|
};
|
|
|
|
#if 0
|
|
@@ -1074,7 +1116,7 @@ static int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
|
|
if (key)
|
|
free(key);
|
|
comdatum = (common_datum_t *) datum;
|
|
- hashtab_map(comdatum->permissions.table, perm_destroy, 0);
|
|
+ (void)hashtab_map(comdatum->permissions.table, perm_destroy, 0);
|
|
hashtab_destroy(comdatum->permissions.table);
|
|
free(datum);
|
|
return 0;
|
|
@@ -1093,7 +1135,7 @@ static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
|
|
if (cladatum == NULL) {
|
|
return 0;
|
|
}
|
|
- hashtab_map(cladatum->permissions.table, perm_destroy, 0);
|
|
+ (void)hashtab_map(cladatum->permissions.table, perm_destroy, 0);
|
|
hashtab_destroy(cladatum->permissions.table);
|
|
constraint = cladatum->constraints;
|
|
while (constraint) {
|
|
@@ -1261,7 +1303,7 @@ void policydb_destroy(policydb_t * p)
|
|
free(p->decl_val_to_struct);
|
|
|
|
for (i = 0; i < SYM_NUM; i++) {
|
|
- hashtab_map(p->scope[i].table, scope_destroy, 0);
|
|
+ (void)hashtab_map(p->scope[i].table, scope_destroy, 0);
|
|
hashtab_destroy(p->scope[i].table);
|
|
}
|
|
avrule_block_list_destroy(p->global);
|
|
@@ -1351,7 +1393,7 @@ void symtabs_destroy(symtab_t * symtab)
|
|
{
|
|
int i;
|
|
for (i = 0; i < SYM_NUM; i++) {
|
|
- hashtab_map(symtab[i].table, destroy_f[i], 0);
|
|
+ (void)hashtab_map(symtab[i].table, destroy_f[i], 0);
|
|
hashtab_destroy(symtab[i].table);
|
|
}
|
|
}
|
|
@@ -1995,8 +2037,11 @@ static int read_cons_helper(policydb_t * p, constraint_node_t ** nodep,
|
|
depth++;
|
|
if (ebitmap_read(&e->names, fp))
|
|
return -1;
|
|
- if (p->policy_type != POLICY_KERN &&
|
|
- type_set_read(e->type_names, fp))
|
|
+ if ((p->policy_type != POLICY_KERN &&
|
|
+ type_set_read(e->type_names, fp)) ||
|
|
+ ((p->policy_type == POLICY_KERN &&
|
|
+ p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) &&
|
|
+ type_set_read(e->type_names, fp)))
|
|
return -1;
|
|
break;
|
|
default:
|
|
@@ -2097,6 +2142,16 @@ static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
|
|
cladatum->default_range = le32_to_cpu(buf[2]);
|
|
}
|
|
|
|
+ if ((p->policy_type == POLICY_KERN &&
|
|
+ p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) ||
|
|
+ (p->policy_type == POLICY_BASE &&
|
|
+ p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) {
|
|
+ rc = next_entry(buf, fp, sizeof(uint32_t));
|
|
+ if (rc < 0)
|
|
+ goto bad;
|
|
+ cladatum->default_type = le32_to_cpu(buf[0]);
|
|
+ }
|
|
+
|
|
if (hashtab_insert(h, key, cladatum))
|
|
goto bad;
|
|
|
|
diff --git a/libsepol/src/services.c b/libsepol/src/services.c
|
|
index 9c2920c..9b42d8d 100644
|
|
--- a/libsepol/src/services.c
|
|
+++ b/libsepol/src/services.c
|
|
@@ -43,6 +43,13 @@
|
|
* Implementation of the security services.
|
|
*/
|
|
|
|
+/* The maximum size of the malloc'd sepol_compute_av_reason_buffer() */
|
|
+#define REASON_BUF_SIZE 30000
|
|
+/* The maximum size of each malloc'd expression buffer */
|
|
+#define EXPR_BUF_SIZE 1000
|
|
+/* Number expressions in a constraint - max seen in MLS policy is 21 */
|
|
+#define EXPR_BUFFERS 30
|
|
+
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
@@ -54,6 +61,7 @@
|
|
#include <sepol/policydb/services.h>
|
|
#include <sepol/policydb/conditional.h>
|
|
#include <sepol/policydb/flask.h>
|
|
+#include <sepol/policydb/util.h>
|
|
|
|
#include "debug.h"
|
|
#include "private.h"
|
|
@@ -70,6 +78,31 @@ static int selinux_enforcing = 1;
|
|
static sidtab_t mysidtab, *sidtab = &mysidtab;
|
|
static policydb_t mypolicydb, *policydb = &mypolicydb;
|
|
|
|
+/* Stack services for RPN to infix conversion. Size is num of expr bufs */
|
|
+char *stack[EXPR_BUFFERS];
|
|
+int tos = 0;
|
|
+
|
|
+void push(char * expr_ptr)
|
|
+{
|
|
+ if (tos >= EXPR_BUFFERS) {
|
|
+ ERR(NULL, "Stack is full");
|
|
+ return;
|
|
+ }
|
|
+ stack[tos] = expr_ptr;
|
|
+ tos++;
|
|
+}
|
|
+
|
|
+char *pop()
|
|
+{
|
|
+ tos--;
|
|
+ if (tos < 0) {
|
|
+ ERR(NULL, "Stack is Empty");
|
|
+ return NULL;
|
|
+ }
|
|
+ return (char *)stack[tos];
|
|
+}
|
|
+/* End Stack services */
|
|
+
|
|
int hidden sepol_set_sidtab(sidtab_t * s)
|
|
{
|
|
sidtab = s;
|
|
@@ -112,20 +145,118 @@ int sepol_set_policydb_from_file(FILE * fp)
|
|
static uint32_t latest_granting = 0;
|
|
|
|
/*
|
|
- * Return the boolean value of a constraint expression
|
|
- * when it is applied to the specified source and target
|
|
+ * This function will process policy version >=
|
|
+ * POLICYDB_VERSION_CONSTRAINT_NAMES as they contain a list
|
|
+ * of types and/or attributes defined in the policy source.
|
|
+ */
|
|
+int get_type_set_list(constraint_expr_t * e, char * e_buf)
|
|
+{
|
|
+ ebitmap_t *types;
|
|
+ types = &e->type_names->types;
|
|
+
|
|
+ int rc = 0;
|
|
+ unsigned int i;
|
|
+ char tmp_buf[100];
|
|
+ /* if ->names is 0, then output string <empty_set> */
|
|
+ int empty_set = 0;
|
|
+
|
|
+ char *list_buf;
|
|
+ list_buf = malloc(EXPR_BUF_SIZE);
|
|
+ if (!list_buf) {
|
|
+ ERR(NULL, "malloc failed to allocate list buffer");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ memset(list_buf, '\0', EXPR_BUF_SIZE);
|
|
+
|
|
+ /*
|
|
+ * Process list of names that have been defined in the policy source.
|
|
+ */
|
|
+ for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) {
|
|
+ if ((rc = ebitmap_get_bit(types, i)) == 0)
|
|
+ continue;
|
|
+ /* Collect entries */
|
|
+ snprintf(tmp_buf, sizeof(tmp_buf), "%s ", policydb->p_type_val_to_name[i]);
|
|
+ strncat(list_buf, tmp_buf, EXPR_BUF_SIZE);
|
|
+ empty_set++;
|
|
+ }
|
|
+
|
|
+ strncat(e_buf, "{ POLICY_SOURCE: ", EXPR_BUF_SIZE);
|
|
+ if (empty_set == 0)
|
|
+ strncat(e_buf, "<empty_set> ", EXPR_BUF_SIZE);
|
|
+ else {
|
|
+ strncat(e_buf, list_buf, EXPR_BUF_SIZE);
|
|
+ }
|
|
+ strncat(e_buf, "} ", EXPR_BUF_SIZE);
|
|
+ free(list_buf);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * If the POLICY_KERN version is < POLICYDB_VERSION_CONSTRAINT_NAMES,
|
|
+ * then just return.
|
|
+ *
|
|
+ * If the POLICY_KERN version is >= POLICYDB_VERSION_CONSTRAINT_NAMES,
|
|
+ * then for 'types' only, read the types_names->types list as it will
|
|
+ * contain a list of types and attributes that were defined in the
|
|
+ * policy source.
|
|
+ */
|
|
+int get_names_list(constraint_expr_t * e, int type, char * e_buf)
|
|
+{
|
|
+ /* If no buffer set then just return. */
|
|
+ if (!e_buf)
|
|
+ return 0;
|
|
+
|
|
+ if (policydb->policy_type == POLICY_KERN &&
|
|
+ policydb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES &&
|
|
+ type == CEXPR_TYPE) {
|
|
+ /* Process >= POLICYDB_VERSION_CONSTRAINT_NAMES with CEXPR_TYPE */
|
|
+ get_type_set_list(e, e_buf);
|
|
+ return 0;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void msgcat(char *e_buf, char *src, char *tgt, char *rel, int failed) {
|
|
+ char tmp_buf[1024];
|
|
+ if (e_buf) {
|
|
+ if (failed)
|
|
+ snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s -Fail-) ",
|
|
+ src, rel, tgt);
|
|
+ else
|
|
+ snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s -Pass-) ",
|
|
+ src, rel, tgt);
|
|
+ strncat(e_buf, tmp_buf, EXPR_BUF_SIZE);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Modified version of constraint_expr_eval that will process each
|
|
+ * constraint as before but adds the information to text buffers that
|
|
+ * will hold various components. The expression will be in RPN format,
|
|
+ * therefore there is a stack based RPN to infix converter to produce
|
|
+ * the final readable constraint.
|
|
+ *
|
|
+ * Return the boolean value of a constraint expression
|
|
+ * when it is applied to the specified source and target
|
|
* security contexts.
|
|
*
|
|
* xcontext is a special beast... It is used by the validatetrans rules
|
|
* only. For these rules, scontext is the context before the transition,
|
|
* tcontext is the context after the transition, and xcontext is the context
|
|
* of the process performing the transition. All other callers of
|
|
- * constraint_expr_eval should pass in NULL for xcontext.
|
|
+ * constraint_expr_eval_reason should pass in NULL for xcontext.
|
|
+ *
|
|
+ * This function will also build a buffer as the constraint is processed
|
|
+ * for analysis. If this option is not required, then:
|
|
+ * 'tclass' should be '0' and r_buf MUST be NULL.
|
|
*/
|
|
-static int constraint_expr_eval(context_struct_t * scontext,
|
|
+static int constraint_expr_eval_reason(context_struct_t * scontext,
|
|
context_struct_t * tcontext,
|
|
context_struct_t * xcontext,
|
|
- constraint_expr_t * cexpr)
|
|
+ sepol_security_class_t tclass,
|
|
+ constraint_node_t *constraint,
|
|
+ char ** r_buf,
|
|
+ unsigned int flags)
|
|
{
|
|
uint32_t val1, val2;
|
|
context_struct_t *c;
|
|
@@ -135,56 +266,138 @@ static int constraint_expr_eval(context_struct_t * scontext,
|
|
int s[CEXPR_MAXDEPTH];
|
|
int sp = -1;
|
|
|
|
- for (e = cexpr; e; e = e->next) {
|
|
+ char tmp_buf[EXPR_BUF_SIZE];
|
|
+
|
|
+ /* The array of expression text buffer pointers and counter */
|
|
+ char *expr_buf[EXPR_BUFFERS] = {NULL};
|
|
+ int expr_counter = 0;
|
|
+ /* Hold class and perm list */
|
|
+ char *class_buf;
|
|
+
|
|
+/*
|
|
+ * Define the s_t_x_num values that make up r1, t2 etc. in text strings
|
|
+ * Set 1 = source, 2 = target, 3 = xcontext for validatetrans
|
|
+ */
|
|
+#define SOURCE 1
|
|
+#define TARGET 2
|
|
+#define XTARGET 3
|
|
+
|
|
+ int s_t_x_num = SOURCE;
|
|
+
|
|
+ /* Set 0 = fail, u = CEXPR_USER, r = CEXPR_ROLE, t = CEXPR_TYPE */
|
|
+ int u_r_t = 0;
|
|
+
|
|
+ char *name1, *name2;
|
|
+ char *src = NULL;
|
|
+ char *tgt = NULL;
|
|
+
|
|
+ int rc = 0, x;
|
|
+
|
|
+ /* Buffer to hold class & perm list */
|
|
+ class_buf = malloc(EXPR_BUF_SIZE);
|
|
+ if (!class_buf) {
|
|
+ ERR(NULL, "malloc failed to allocate class buffer");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ memset(class_buf, '\0', EXPR_BUF_SIZE);
|
|
+
|
|
+ /* Get constraint statement type */
|
|
+ strncpy(tmp_buf, "constrain ", sizeof(tmp_buf));
|
|
+ for (e = constraint->expr; e; e = e->next) {
|
|
+ if (e->attr >= CEXPR_L1L2) {
|
|
+ strncpy(tmp_buf, "mlsconstrain ", sizeof(tmp_buf));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ strncat(class_buf, tmp_buf, EXPR_BUF_SIZE);
|
|
+
|
|
+ /* Get class entry */
|
|
+ snprintf(tmp_buf, sizeof(tmp_buf), "%s ", policydb->p_class_val_to_name[tclass - 1]);
|
|
+ strncat(class_buf, tmp_buf, EXPR_BUF_SIZE);
|
|
+
|
|
+ /* Get permission entries from the constraint node. */
|
|
+ snprintf(tmp_buf, sizeof(tmp_buf), "{%s } (", sepol_av_to_string(policydb, tclass,
|
|
+ constraint->permissions));
|
|
+ strncat(class_buf, tmp_buf, EXPR_BUF_SIZE);
|
|
+
|
|
+ /* Original function but with buffer support */
|
|
+ for (e = constraint->expr; e; e = e->next) {
|
|
+ /* malloc a buffer to store each expression text component */
|
|
+ expr_buf[expr_counter] = malloc(EXPR_BUF_SIZE);
|
|
+ if (!expr_buf[expr_counter]) {
|
|
+ ERR(NULL, "malloc failed to allocate expr buffer");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ memset(expr_buf[expr_counter], '\0', EXPR_BUF_SIZE);
|
|
+
|
|
+ /* Now process each expression of the constraint */
|
|
switch (e->expr_type) {
|
|
case CEXPR_NOT:
|
|
BUG_ON(sp < 0);
|
|
s[sp] = !s[sp];
|
|
+ if (*r_buf)
|
|
+ strncat(expr_buf[expr_counter], "not", EXPR_BUF_SIZE);
|
|
break;
|
|
case CEXPR_AND:
|
|
BUG_ON(sp < 1);
|
|
sp--;
|
|
s[sp] &= s[sp + 1];
|
|
+ if (*r_buf)
|
|
+ strncat(expr_buf[expr_counter], "and", EXPR_BUF_SIZE);
|
|
break;
|
|
case CEXPR_OR:
|
|
BUG_ON(sp < 1);
|
|
sp--;
|
|
s[sp] |= s[sp + 1];
|
|
+ if (*r_buf)
|
|
+ strncat(expr_buf[expr_counter], "or", EXPR_BUF_SIZE);
|
|
break;
|
|
case CEXPR_ATTR:
|
|
if (sp == (CEXPR_MAXDEPTH - 1))
|
|
- return 0;
|
|
+ goto out;
|
|
+
|
|
switch (e->attr) {
|
|
case CEXPR_USER:
|
|
val1 = scontext->user;
|
|
val2 = tcontext->user;
|
|
+ free(src); src = strdup("u1");
|
|
+ free(tgt); tgt = strdup("u2");
|
|
break;
|
|
case CEXPR_TYPE:
|
|
val1 = scontext->type;
|
|
val2 = tcontext->type;
|
|
+ free(src); src = strdup("t1");
|
|
+ free(tgt); tgt = strdup("t2");
|
|
break;
|
|
case CEXPR_ROLE:
|
|
val1 = scontext->role;
|
|
val2 = tcontext->role;
|
|
r1 = policydb->role_val_to_struct[val1 - 1];
|
|
r2 = policydb->role_val_to_struct[val2 - 1];
|
|
+ if (*r_buf) {
|
|
+ name1 = policydb->p_role_val_to_name[r1->s.value - 1];
|
|
+ name2 = policydb->p_role_val_to_name[r2->s.value - 1];
|
|
+ snprintf(tmp_buf,sizeof(tmp_buf), "r1=%s", name1);
|
|
+ free(src); src = strdup(tmp_buf);
|
|
+ snprintf(tmp_buf,sizeof(tmp_buf), "r2=%s ", name2);
|
|
+ free(tgt); tgt = strdup(tmp_buf);
|
|
+ }
|
|
switch (e->op) {
|
|
case CEXPR_DOM:
|
|
- s[++sp] =
|
|
- ebitmap_get_bit(&r1->dominates,
|
|
- val2 - 1);
|
|
+ s[++sp] = ebitmap_get_bit(&r1->dominates, val2 - 1);
|
|
+ msgcat(expr_buf[expr_counter++], src, tgt, "dom",
|
|
+ s[sp] == 0);
|
|
continue;
|
|
case CEXPR_DOMBY:
|
|
- s[++sp] =
|
|
- ebitmap_get_bit(&r2->dominates,
|
|
- val1 - 1);
|
|
+ s[++sp] = ebitmap_get_bit(&r2->dominates, val1 - 1);
|
|
+ msgcat(expr_buf[expr_counter++], src, tgt,
|
|
+ "domby", s[sp] == 0);
|
|
continue;
|
|
case CEXPR_INCOMP:
|
|
- s[++sp] =
|
|
- (!ebitmap_get_bit
|
|
- (&r1->dominates, val2 - 1)
|
|
- && !ebitmap_get_bit(&r2->dominates,
|
|
- val1 - 1));
|
|
+ s[++sp] = (!ebitmap_get_bit(&r1->dominates, val2 - 1)
|
|
+ && !ebitmap_get_bit(&r2->dominates, val1 - 1));
|
|
+ msgcat(expr_buf[expr_counter++], src, tgt,
|
|
+ "incomp", s[sp] == 0);
|
|
continue;
|
|
default:
|
|
break;
|
|
@@ -193,110 +406,286 @@ static int constraint_expr_eval(context_struct_t * scontext,
|
|
case CEXPR_L1L2:
|
|
l1 = &(scontext->range.level[0]);
|
|
l2 = &(tcontext->range.level[0]);
|
|
+ free(src); src = strdup("l1");
|
|
+ free(tgt); tgt = strdup("l2");
|
|
goto mls_ops;
|
|
case CEXPR_L1H2:
|
|
l1 = &(scontext->range.level[0]);
|
|
l2 = &(tcontext->range.level[1]);
|
|
+ free(src); src = strdup("l1");
|
|
+ free(tgt); tgt = strdup("h2");
|
|
goto mls_ops;
|
|
case CEXPR_H1L2:
|
|
l1 = &(scontext->range.level[1]);
|
|
l2 = &(tcontext->range.level[0]);
|
|
+ free(src); src = strdup("h1");
|
|
+ free(tgt); tgt = strdup("L2");
|
|
goto mls_ops;
|
|
case CEXPR_H1H2:
|
|
l1 = &(scontext->range.level[1]);
|
|
l2 = &(tcontext->range.level[1]);
|
|
+ free(src); src = strdup("h1");
|
|
+ free(tgt); tgt = strdup("h2");
|
|
goto mls_ops;
|
|
case CEXPR_L1H1:
|
|
l1 = &(scontext->range.level[0]);
|
|
l2 = &(scontext->range.level[1]);
|
|
+ free(src); src = strdup("l1");
|
|
+ free(tgt); tgt = strdup("h1");
|
|
goto mls_ops;
|
|
case CEXPR_L2H2:
|
|
l1 = &(tcontext->range.level[0]);
|
|
l2 = &(tcontext->range.level[1]);
|
|
- goto mls_ops;
|
|
- mls_ops:
|
|
+ free(src); src = strdup("l2");
|
|
+ free(tgt); tgt = strdup("h2");
|
|
+ mls_ops:
|
|
switch (e->op) {
|
|
case CEXPR_EQ:
|
|
s[++sp] = mls_level_eq(l1, l2);
|
|
+ msgcat(expr_buf[expr_counter++], src, tgt,
|
|
+ "eq", s[sp] == 0);
|
|
continue;
|
|
case CEXPR_NEQ:
|
|
s[++sp] = !mls_level_eq(l1, l2);
|
|
+ msgcat(expr_buf[expr_counter++], src, tgt, "neq",
|
|
+ s[sp] == 0);
|
|
continue;
|
|
case CEXPR_DOM:
|
|
s[++sp] = mls_level_dom(l1, l2);
|
|
+ msgcat(expr_buf[expr_counter++], src, tgt, "dom",
|
|
+ s[sp] == 0);
|
|
continue;
|
|
case CEXPR_DOMBY:
|
|
s[++sp] = mls_level_dom(l2, l1);
|
|
+ msgcat(expr_buf[expr_counter++], src, tgt,
|
|
+ "domby", s[sp] == 0);
|
|
continue;
|
|
case CEXPR_INCOMP:
|
|
s[++sp] = mls_level_incomp(l2, l1);
|
|
+ msgcat(expr_buf[expr_counter++], src, tgt,
|
|
+ "incomp", s[sp] == 0);
|
|
continue;
|
|
default:
|
|
BUG();
|
|
- return 0;
|
|
+ goto out;
|
|
}
|
|
break;
|
|
default:
|
|
BUG();
|
|
- return 0;
|
|
+ goto out;
|
|
}
|
|
|
|
switch (e->op) {
|
|
case CEXPR_EQ:
|
|
s[++sp] = (val1 == val2);
|
|
+ msgcat(expr_buf[expr_counter], src, tgt, "eq", s[sp] == 0);
|
|
break;
|
|
case CEXPR_NEQ:
|
|
s[++sp] = (val1 != val2);
|
|
+ msgcat(expr_buf[expr_counter], src, tgt, "neq", s[sp] == 0);
|
|
break;
|
|
default:
|
|
BUG();
|
|
- return 0;
|
|
+ goto out;
|
|
}
|
|
break;
|
|
case CEXPR_NAMES:
|
|
if (sp == (CEXPR_MAXDEPTH - 1))
|
|
- return 0;
|
|
+ goto out;
|
|
+ s_t_x_num = SOURCE;
|
|
c = scontext;
|
|
- if (e->attr & CEXPR_TARGET)
|
|
+ if (e->attr & CEXPR_TARGET) {
|
|
+ s_t_x_num = TARGET;
|
|
c = tcontext;
|
|
- else if (e->attr & CEXPR_XTARGET) {
|
|
+ } else if (e->attr & CEXPR_XTARGET) {
|
|
+ s_t_x_num = XTARGET;
|
|
c = xcontext;
|
|
- if (!c) {
|
|
- BUG();
|
|
- return 0;
|
|
- }
|
|
}
|
|
- if (e->attr & CEXPR_USER)
|
|
+ if (!c) {
|
|
+ BUG();
|
|
+ goto out;
|
|
+ }
|
|
+ if (e->attr & CEXPR_USER) {
|
|
+ u_r_t = CEXPR_USER;
|
|
val1 = c->user;
|
|
- else if (e->attr & CEXPR_ROLE)
|
|
+ if (*r_buf) {
|
|
+ name1 = policydb->p_user_val_to_name[val1 - 1];
|
|
+ snprintf(tmp_buf,sizeof(tmp_buf), "u%d=%s ",
|
|
+ s_t_x_num, name1);
|
|
+ free(src); src = strdup(tmp_buf);
|
|
+ }
|
|
+ }
|
|
+ else if (e->attr & CEXPR_ROLE) {
|
|
+ u_r_t = CEXPR_ROLE;
|
|
val1 = c->role;
|
|
- else if (e->attr & CEXPR_TYPE)
|
|
+ if (*r_buf) {
|
|
+ name1 = policydb->p_role_val_to_name[val1 - 1];
|
|
+ snprintf(tmp_buf,sizeof(tmp_buf),
|
|
+ "r%d=%s ", s_t_x_num, name1);
|
|
+ free(src); src = strdup(tmp_buf);
|
|
+ }
|
|
+ }
|
|
+ else if (e->attr & CEXPR_TYPE) {
|
|
+ u_r_t = CEXPR_TYPE;
|
|
val1 = c->type;
|
|
+ if (*r_buf) {
|
|
+ name1 = policydb->p_type_val_to_name[val1 - 1];
|
|
+ snprintf(tmp_buf,sizeof(tmp_buf),
|
|
+ "t%d=%s ", s_t_x_num, name1);
|
|
+ free(src); src = strdup(tmp_buf);
|
|
+ }
|
|
+ }
|
|
else {
|
|
BUG();
|
|
- return 0;
|
|
+ goto out;
|
|
}
|
|
|
|
switch (e->op) {
|
|
case CEXPR_EQ:
|
|
+ switch (u_r_t) {
|
|
+ case CEXPR_USER:
|
|
+ free(tgt); tgt=strdup("USER_ENTRY");
|
|
+ break;
|
|
+ case CEXPR_ROLE:
|
|
+ free(tgt); tgt=strdup("ROLE_ENTRY");
|
|
+ break;
|
|
+ case CEXPR_TYPE:
|
|
+ free(tgt); tgt=strdup("TYPE_ENTRY");
|
|
+ break;
|
|
+ default:
|
|
+ ERR(NULL, "unrecognized u_r_t Value: %d", u_r_t);
|
|
+ break;
|
|
+ }
|
|
+
|
|
s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
|
|
+ msgcat(expr_buf[expr_counter], src, tgt, "eq", s[sp] == 0);
|
|
+ if (s[sp] == 0) {
|
|
+ get_names_list(e, u_r_t, expr_buf[expr_counter]);
|
|
+ }
|
|
break;
|
|
+
|
|
case CEXPR_NEQ:
|
|
+ switch (u_r_t) {
|
|
+ case CEXPR_USER:
|
|
+ free(tgt); tgt=strdup("USER_ENTRY");
|
|
+ break;
|
|
+ case CEXPR_ROLE:
|
|
+ free(tgt); tgt=strdup("ROLE_ENTRY");
|
|
+ break;
|
|
+ case CEXPR_TYPE:
|
|
+ free(tgt); tgt=strdup("TYPE_ENTRY");
|
|
+ break;
|
|
+ default:
|
|
+ ERR(NULL, "unrecognized u_r_t Value: %d", u_r_t);
|
|
+ break;
|
|
+ }
|
|
+
|
|
s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
|
|
+ msgcat(expr_buf[expr_counter], src, tgt, "neq", s[sp] == 0);
|
|
+ if (s[sp] == 0) {
|
|
+ get_names_list(e, u_r_t, expr_buf[expr_counter]);
|
|
+ }
|
|
break;
|
|
default:
|
|
BUG();
|
|
- return 0;
|
|
+ goto out;
|
|
}
|
|
break;
|
|
default:
|
|
BUG();
|
|
- return 0;
|
|
+ goto out;
|
|
}
|
|
+ expr_counter++;
|
|
}
|
|
|
|
+ /*
|
|
+ * At this point each expression of the constraint is in
|
|
+ * expr_buf[n+1] and in RPN format. Now convert to 'infix'
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * Zero expr_counter to detect if 'BUG(); goto out;' was called
|
|
+ * as we need to release any used expr_buf malloc's. Normally they
|
|
+ * are released by the RPN to infix code.
|
|
+ */
|
|
+ expr_counter = 0;
|
|
+
|
|
+ /* The array of expression answer buffer pointers and counter */
|
|
+ char *answer_buf[EXPR_BUFFERS] = {NULL};
|
|
+ int answer_counter = 0;
|
|
+ /* pop operands */
|
|
+ char *a;
|
|
+ char *b;
|
|
+ int a_len, b_len;
|
|
+
|
|
+ /* Convert constraint from RPN to infix notation. */
|
|
+ for (x = 0; expr_buf[x] != NULL; x++) {
|
|
+ if (strncmp(expr_buf[x], "and", 3) == 0 || strncmp(expr_buf[x],
|
|
+ "or", 2) == 0) {
|
|
+ b = pop();
|
|
+ b_len = strlen(b);
|
|
+ a = pop();
|
|
+ a_len = strlen(a);
|
|
+
|
|
+ /* get a buffer to hold the answer */
|
|
+ answer_buf[answer_counter] = malloc(a_len + b_len + 8);
|
|
+ if (!answer_buf[answer_counter]) {
|
|
+ ERR(NULL, "malloc failed to allocate answer buffer");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ memset(answer_buf[answer_counter], '\0', a_len + b_len + 8);
|
|
+
|
|
+ sprintf(answer_buf[answer_counter], "%s %s %s", a, expr_buf[x], b);
|
|
+ push(answer_buf[answer_counter++]);
|
|
+ free(a);
|
|
+ free(b);
|
|
+ } else if (strncmp(expr_buf[x], "not", 3) == 0) {
|
|
+ b = pop();
|
|
+ b_len = strlen(b);
|
|
+
|
|
+ answer_buf[answer_counter] = malloc(b_len + 8);
|
|
+ if (!answer_buf[answer_counter]) {
|
|
+ ERR(NULL, "malloc failed to allocate answer buffer");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ memset(answer_buf[answer_counter], '\0', b_len + 8);
|
|
+
|
|
+ if (strncmp(b, "not", 3) == 0)
|
|
+ sprintf(answer_buf[answer_counter], "%s (%s)", expr_buf[x], b);
|
|
+ else
|
|
+ sprintf(answer_buf[answer_counter], "%s%s", expr_buf[x], b);
|
|
+ push(answer_buf[answer_counter++]);
|
|
+ free(b);
|
|
+ } else {
|
|
+ push(expr_buf[x]);
|
|
+ }
|
|
+ }
|
|
+ /* Get the final answer from tos and build constraint text */
|
|
+ a = pop();
|
|
+
|
|
+ if (*r_buf) {
|
|
+ if ((s[0] == 0) || ((s[0] == 1 && (flags & SHOW_GRANTED) == SHOW_GRANTED))) {
|
|
+ strncat(*r_buf, class_buf, REASON_BUF_SIZE);
|
|
+ strncat(*r_buf, a, REASON_BUF_SIZE);
|
|
+ strncat(*r_buf, "); ", REASON_BUF_SIZE);
|
|
+ /* Constraint calculation: rc = 0 is denied, rc = 1 is granted */
|
|
+ sprintf(tmp_buf,"Constraint %s\n", s[0] ? "GRANTED" : "DENIED");
|
|
+ strncat(*r_buf, tmp_buf, REASON_BUF_SIZE);
|
|
+ }
|
|
+ }
|
|
+ free(a);
|
|
+ rc = s[0];
|
|
+
|
|
+out:
|
|
+ free(class_buf);
|
|
+ free(src);
|
|
+ free(tgt);
|
|
+ if (expr_counter) {
|
|
+ for (x = 0; expr_buf[x] != NULL; x++)
|
|
+ free(expr_buf[x]);
|
|
+ }
|
|
BUG_ON(sp != 0);
|
|
- return s[0];
|
|
+ return rc;
|
|
}
|
|
|
|
/*
|
|
@@ -308,7 +697,9 @@ static int context_struct_compute_av(context_struct_t * scontext,
|
|
sepol_security_class_t tclass,
|
|
sepol_access_vector_t requested,
|
|
struct sepol_av_decision *avd,
|
|
- unsigned int *reason)
|
|
+ unsigned int *reason,
|
|
+ char *r_buf,
|
|
+ unsigned int flags)
|
|
{
|
|
constraint_node_t *constraint;
|
|
struct role_allow *ra;
|
|
@@ -383,8 +774,8 @@ static int context_struct_compute_av(context_struct_t * scontext,
|
|
constraint = tclass_datum->constraints;
|
|
while (constraint) {
|
|
if ((constraint->permissions & (avd->allowed)) &&
|
|
- !constraint_expr_eval(scontext, tcontext, NULL,
|
|
- constraint->expr)) {
|
|
+ !constraint_expr_eval_reason(scontext, tcontext, NULL,
|
|
+ tclass, constraint, &r_buf, flags)) {
|
|
avd->allowed =
|
|
(avd->allowed) & ~(constraint->permissions);
|
|
}
|
|
@@ -459,8 +850,8 @@ int hidden sepol_validate_transition(sepol_security_id_t oldsid,
|
|
|
|
constraint = tclass_datum->validatetrans;
|
|
while (constraint) {
|
|
- if (!constraint_expr_eval(ocontext, ncontext, tcontext,
|
|
- constraint->expr)) {
|
|
+ if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext,
|
|
+ 0, constraint, NULL, 0)) {
|
|
return -EPERM;
|
|
}
|
|
constraint = constraint->next;
|
|
@@ -493,11 +884,58 @@ int hidden sepol_compute_av_reason(sepol_security_id_t ssid,
|
|
}
|
|
|
|
rc = context_struct_compute_av(scontext, tcontext, tclass,
|
|
- requested, avd, reason);
|
|
+ requested, avd, reason, NULL, 0);
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
+/*
|
|
+ * sepol_compute_av_reason_buffer - the reason buffer is malloc'd
|
|
+ * to REASON_BUF_SIZE that seems okay for the Reference Policy.
|
|
+ * TODO manage size using realloc at some stage.
|
|
+ */
|
|
+int hidden sepol_compute_av_reason_buffer(sepol_security_id_t ssid,
|
|
+ sepol_security_id_t tsid,
|
|
+ sepol_security_class_t tclass,
|
|
+ sepol_access_vector_t requested,
|
|
+ struct sepol_av_decision *avd,
|
|
+ unsigned int *reason,
|
|
+ char **reason_buf,
|
|
+ unsigned int flags)
|
|
+{
|
|
+ char *r_buf = NULL;
|
|
+
|
|
+ r_buf = malloc(REASON_BUF_SIZE);
|
|
+ if (!r_buf) {
|
|
+ ERR(NULL, "malloc failed to allocate constraint reason buffer");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ memset(r_buf, '\0', REASON_BUF_SIZE);
|
|
+
|
|
+ context_struct_t *scontext = 0, *tcontext = 0;
|
|
+ int rc = 0;
|
|
+
|
|
+ scontext = sepol_sidtab_search(sidtab, ssid);
|
|
+ if (!scontext) {
|
|
+ ERR(NULL, "unrecognized SID %d", ssid);
|
|
+ rc = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+ tcontext = sepol_sidtab_search(sidtab, tsid);
|
|
+ if (!tcontext) {
|
|
+ ERR(NULL, "unrecognized SID %d", tsid);
|
|
+ rc = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ rc = context_struct_compute_av(scontext, tcontext, tclass,
|
|
+ requested, avd, reason, r_buf, flags);
|
|
+ *reason_buf = r_buf;
|
|
+
|
|
+ out:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
int hidden sepol_compute_av(sepol_security_id_t ssid,
|
|
sepol_security_id_t tsid,
|
|
sepol_security_class_t tclass,
|
|
@@ -510,6 +948,66 @@ int hidden sepol_compute_av(sepol_security_id_t ssid,
|
|
}
|
|
|
|
/*
|
|
+ * Return a class ID associated with the class string specified by
|
|
+ * class_name.
|
|
+ */
|
|
+int hidden sepol_class_name_to_id(const char *class_name,
|
|
+ sepol_security_class_t *tclass)
|
|
+{
|
|
+ char *class = NULL;
|
|
+ sepol_security_class_t id;
|
|
+
|
|
+ for (id = 1; ; id++) {
|
|
+ if ((class = policydb->p_class_val_to_name[id - 1]) == NULL) {
|
|
+ ERR(NULL, "could not convert %s to class id", class_name);
|
|
+ return STATUS_ERR;
|
|
+ }
|
|
+ if ((strcmp(class, class_name)) == 0) {
|
|
+ *tclass = id;
|
|
+ return STATUS_SUCCESS;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Return access vector bit associated with the class ID and permission
|
|
+ * string.
|
|
+ */
|
|
+int hidden sepol_perm_name_to_av(sepol_security_class_t tclass,
|
|
+ const char *perm_name,
|
|
+ sepol_access_vector_t *av)
|
|
+{
|
|
+ class_datum_t *tclass_datum;
|
|
+ perm_datum_t *perm_datum;
|
|
+
|
|
+ if (!tclass || tclass > policydb->p_classes.nprim) {
|
|
+ ERR(NULL, "unrecognized class %d", tclass);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ tclass_datum = policydb->class_val_to_struct[tclass - 1];
|
|
+
|
|
+ /* Check for unique perms then the common ones */
|
|
+ perm_datum = (perm_datum_t *)
|
|
+ hashtab_search(tclass_datum->permissions.table,
|
|
+ (hashtab_key_t)perm_name);
|
|
+ if (perm_datum != NULL) {
|
|
+ *av = 0x1 << (perm_datum->s.value - 1);
|
|
+ return STATUS_SUCCESS;
|
|
+ }
|
|
+
|
|
+ perm_datum = (perm_datum_t *)
|
|
+ hashtab_search(tclass_datum->comdatum->permissions.table,
|
|
+ (hashtab_key_t)perm_name);
|
|
+ if (perm_datum != NULL) {
|
|
+ *av = 0x1 << (perm_datum->s.value - 1);
|
|
+ return STATUS_SUCCESS;
|
|
+ }
|
|
+
|
|
+ ERR(NULL, "could not convert %s to av bit", perm_name);
|
|
+ return STATUS_ERR;
|
|
+}
|
|
+
|
|
+/*
|
|
* Write the security context string representation of
|
|
* the context associated with `sid' into a dynamically
|
|
* allocated string of the correct size. Set `*scontext'
|
|
@@ -1337,7 +1835,7 @@ int hidden sepol_get_user_sids(sepol_security_id_t fromsid,
|
|
rc = context_struct_compute_av(fromcon, &usercon,
|
|
SECCLASS_PROCESS,
|
|
PROCESS__TRANSITION,
|
|
- &avd, &reason);
|
|
+ &avd, &reason, NULL, 0);
|
|
if (rc || !(avd.allowed & PROCESS__TRANSITION))
|
|
continue;
|
|
rc = sepol_sidtab_context_to_sid(sidtab, &usercon,
|
|
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
|
|
index 22e6143..6fe73e6 100644
|
|
--- a/libsepol/src/write.c
|
|
+++ b/libsepol/src/write.c
|
|
@@ -893,8 +893,11 @@ static int write_cons_helper(policydb_t * p,
|
|
if (ebitmap_write(&e->names, fp)) {
|
|
return POLICYDB_ERROR;
|
|
}
|
|
- if (p->policy_type != POLICY_KERN &&
|
|
- type_set_write(e->type_names, fp)) {
|
|
+ if ((p->policy_type != POLICY_KERN &&
|
|
+ type_set_write(e->type_names, fp)) ||
|
|
+ (p->policy_type == POLICY_KERN &&
|
|
+ (p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) &&
|
|
+ type_set_write(e->type_names, fp))) {
|
|
return POLICYDB_ERROR;
|
|
}
|
|
break;
|
|
@@ -988,6 +991,16 @@ static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
|
|
return POLICYDB_ERROR;
|
|
}
|
|
|
|
+ if ((p->policy_type == POLICY_KERN &&
|
|
+ p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) ||
|
|
+ (p->policy_type == POLICY_BASE &&
|
|
+ p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) {
|
|
+ buf[0] = cpu_to_le32(cladatum->default_type);
|
|
+ items = put_entry(buf, sizeof(uint32_t), 1, fp);
|
|
+ if (items != 1)
|
|
+ return POLICYDB_ERROR;
|
|
+ }
|
|
+
|
|
return POLICYDB_SUCCESS;
|
|
}
|
|
|
|
@@ -1795,34 +1808,38 @@ static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
|
|
uint32_t static_buf[32], *dyn_buf = NULL, *buf;
|
|
size_t key_len = strlen(key);
|
|
unsigned int items = 2 + scope->decl_ids_len, i;
|
|
+ int rc;
|
|
|
|
+ buf = static_buf;
|
|
if (items >= (sizeof(static_buf) / 4)) {
|
|
/* too many things required, so dynamically create a
|
|
* buffer. this would have been easier with C99's
|
|
* dynamic arrays... */
|
|
- if ((dyn_buf = malloc(items * sizeof(*dyn_buf))) == NULL) {
|
|
- return POLICYDB_ERROR;
|
|
- }
|
|
+ rc = POLICYDB_ERROR;
|
|
+ dyn_buf = malloc(items * sizeof(*dyn_buf));
|
|
+ if (!dyn_buf)
|
|
+ goto err;
|
|
buf = dyn_buf;
|
|
- } else {
|
|
- buf = static_buf;
|
|
}
|
|
buf[0] = cpu_to_le32(key_len);
|
|
+
|
|
+ rc = POLICYDB_ERROR;
|
|
if (put_entry(buf, sizeof(*buf), 1, fp) != 1 ||
|
|
- put_entry(key, 1, key_len, fp) != key_len) {
|
|
- return POLICYDB_ERROR;
|
|
- }
|
|
+ put_entry(key, 1, key_len, fp) != key_len)
|
|
+ goto err;
|
|
buf[0] = cpu_to_le32(scope->scope);
|
|
buf[1] = cpu_to_le32(scope->decl_ids_len);
|
|
- for (i = 0; i < scope->decl_ids_len; i++) {
|
|
+
|
|
+ for (i = 0; i < scope->decl_ids_len; i++)
|
|
buf[2 + i] = cpu_to_le32(scope->decl_ids[i]);
|
|
- }
|
|
- if (put_entry(buf, sizeof(*buf), items, fp) != items) {
|
|
- free(dyn_buf);
|
|
- return POLICYDB_ERROR;
|
|
- }
|
|
+
|
|
+ rc = POLICYDB_ERROR;
|
|
+ if (put_entry(buf, sizeof(*buf), items, fp) != items)
|
|
+ goto err;
|
|
+ rc = POLICYDB_SUCCESS;
|
|
+err:
|
|
free(dyn_buf);
|
|
- return POLICYDB_SUCCESS;
|
|
+ return rc;
|
|
}
|
|
|
|
static int type_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
|
|
@@ -2006,7 +2023,7 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
|
|
((p->policy_type == POLICY_KERN) ||
|
|
(p->policy_type != POLICY_KERN &&
|
|
p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB)))
|
|
- hashtab_map(p->symtab[i].table, role_attr_uncount, &buf[1]);
|
|
+ (void)hashtab_map(p->symtab[i].table, role_attr_uncount, &buf[1]);
|
|
|
|
buf[1] = cpu_to_le32(buf[1]);
|
|
items = put_entry(buf, sizeof(uint32_t), 2, fp);
|