mirror of
https://github.com/SELinuxProject/setools
synced 2025-02-23 15:47:00 +00:00
1398 lines
36 KiB
C
1398 lines
36 KiB
C
/**
|
|
* @file
|
|
* Implementation of the interface for loading and using an extended
|
|
* policy image.
|
|
*
|
|
* @author Jeremy A. Mowery jmowery@tresys.com
|
|
* @author Jason Tang jtang@tresys.com
|
|
* @author Jeremy Solt jsolt@tresys.com
|
|
*
|
|
* Copyright (C) 2006-2008 Tresys Technology, LLC
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <sepol/policydb/policydb.h>
|
|
#include <sepol/policydb/conditional.h>
|
|
#include <sepol/policydb/avtab.h>
|
|
#include <sepol/policydb/hashtab.h>
|
|
#include <sepol/policydb/flask.h>
|
|
#include <sepol/policydb/ebitmap.h>
|
|
#include <sepol/policydb/expand.h>
|
|
#ifdef HAVE_SEPOL_ERRCODES
|
|
#include <sepol/errcodes.h>
|
|
#endif
|
|
#include <qpol/policy.h>
|
|
#include <qpol/policy_extend.h>
|
|
#include <qpol/iterator.h>
|
|
#include <selinux/selinux.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "qpol_internal.h"
|
|
#include "iterator_internal.h"
|
|
#include "syn_rule_internal.h"
|
|
|
|
#ifdef SETOOLS_DEBUG
|
|
#include <math.h>
|
|
#endif
|
|
|
|
#define OBJECT_R "object_r"
|
|
|
|
#define QPOL_SYN_RULE_TABLE_BITS 16
|
|
#define QPOL_SYN_RULE_TABLE_SIZE (1 << QPOL_SYN_RULE_TABLE_BITS)
|
|
#define QPOL_SYN_RULE_TABLE_MASK (QPOL_SYN_RULE_TABLE_SIZE - 1)
|
|
|
|
/* original hashing function below */
|
|
/*
|
|
#define QPOL_SYN_RULE_TABLE_HASH(rule_key) \
|
|
((rule_key->class_val + \
|
|
(rule_key->target_val << 2) +\
|
|
(rule_key->source_val << 9)) & \
|
|
QPOL_SYN_RULE_TABLE_MASK)
|
|
*/
|
|
|
|
/* new hashing function, introduced in SETools 3.3 */
|
|
#define QPOL_SYN_RULE_TABLE_HASH(rule_key) \
|
|
(((((rule_key->source_val & 0xff) << 8) | (rule_key->target_val & 0xff)) ^ \
|
|
(rule_key->class_val & 0xf) ^ \
|
|
((int) ((size_t) rule_key->cond) & 0xfff0)) & QPOL_SYN_RULE_TABLE_MASK)
|
|
|
|
typedef struct qpol_syn_rule_key
|
|
{
|
|
uint32_t rule_type;
|
|
uint32_t source_val;
|
|
uint32_t target_val;
|
|
uint32_t class_val;
|
|
cond_node_t *cond;
|
|
} qpol_syn_rule_key_t;
|
|
|
|
typedef struct qpol_syn_rule_list
|
|
{
|
|
struct qpol_syn_rule *rule;
|
|
struct qpol_syn_rule_list *next;
|
|
} qpol_syn_rule_list_t;
|
|
|
|
typedef struct qpol_syn_rule_node
|
|
{
|
|
qpol_syn_rule_key_t key;
|
|
qpol_syn_rule_list_t *rules;
|
|
struct qpol_syn_rule_node *next;
|
|
} qpol_syn_rule_node_t;
|
|
|
|
typedef struct qpol_syn_rule_table
|
|
{
|
|
qpol_syn_rule_node_t **buckets;
|
|
} qpol_syn_rule_table_t;
|
|
|
|
typedef struct qpol_extended_image
|
|
{
|
|
qpol_syn_rule_table_t *syn_rule_table;
|
|
struct qpol_syn_rule **syn_rule_master_list;
|
|
size_t master_list_sz;
|
|
} qpol_extended_image_t;
|
|
|
|
struct extend_bogus_alias_struct
|
|
{
|
|
qpol_policy_t *q;
|
|
int num_bogus_aliases;
|
|
};
|
|
|
|
static int extend_find_bogus_alias(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *args)
|
|
{
|
|
struct extend_bogus_alias_struct *e = (struct extend_bogus_alias_struct *)args;
|
|
/* within libqpol, qpol_type_t is the same a libsepol's type_datum_t */
|
|
qpol_type_t *qtype = (qpol_type_t *) datum;
|
|
type_datum_t *type = (type_datum_t *) datum;
|
|
unsigned char isalias;
|
|
qpol_type_get_isalias(e->q, qtype, &isalias);
|
|
return isalias && type->s.value == 0;
|
|
}
|
|
|
|
static void extend_remove_bogus_alias(hashtab_key_t key, hashtab_datum_t datum, void *args)
|
|
{
|
|
struct extend_bogus_alias_struct *e = (struct extend_bogus_alias_struct *)args;
|
|
free(key);
|
|
type_datum_t *type = (type_datum_t *) datum;
|
|
type_datum_destroy(type);
|
|
free(type);
|
|
e->num_bogus_aliases++;
|
|
}
|
|
|
|
/**
|
|
* Search the policy for aliases that have a value of 0. These come
|
|
* from modular policies with disabled aliases, but end up being
|
|
* written to the policy anyways due to a bug in libsepol. These
|
|
* bogus aliases are removed from the policy.
|
|
* @param policy Policy that may contain broken aliases. This policy
|
|
* will be altered by this function.
|
|
* @return 0 on success and < 0 on failure; if the call fails, errno
|
|
* will be set. On failure, the policy state may be inconsistent.
|
|
*/
|
|
static int qpol_policy_remove_bogus_aliases(qpol_policy_t * policy)
|
|
{
|
|
policydb_t *db = NULL;
|
|
|
|
if (policy == NULL) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
db = &policy->p->p;
|
|
struct extend_bogus_alias_struct e = { policy, 0 };
|
|
hashtab_map_remove_on_error(db->p_types.table, extend_find_bogus_alias, extend_remove_bogus_alias, &e);
|
|
|
|
#ifdef SETOOLS_DEBUG
|
|
if (e.num_bogus_aliases > 0) {
|
|
WARN(policy, "%s", "This policy contained disabled aliases; they have been removed.");
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Builds data for the attributes and inserts them into the policydb.
|
|
* This function modifies the policydb. Names created for attributes
|
|
* are of the form @ttr<value> where value is the value of the attribute
|
|
* as a four digit number (prepended with 0's as needed).
|
|
* @param policy The policy from which to read the attribute map and
|
|
* create the type data for the attributes. This policy will be altered
|
|
* by this function.
|
|
* @return Returns 0 on success and < 0 on failure; if the call fails,
|
|
* errno will be set. On failure, the policy state may be inconsistent
|
|
* especially in the case where the hashtab functions return the error.
|
|
*/
|
|
static int qpol_policy_build_attrs_from_map(qpol_policy_t * policy)
|
|
{
|
|
policydb_t *db = NULL;
|
|
size_t i;
|
|
uint32_t bit = 0, count = 0;
|
|
ebitmap_node_t *node = NULL;
|
|
type_datum_t *tmp_type = NULL, *orig_type;
|
|
char *tmp_name = NULL, buff[10];
|
|
int error = 0, retv;
|
|
|
|
INFO(policy, "%s", "Generating attributes for policy. (Step 4 of 5)");
|
|
if (policy == NULL) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
db = &policy->p->p;
|
|
|
|
memset(&buff, 0, 10 * sizeof(char));
|
|
|
|
for (i = 0; i < db->p_types.nprim; i++) {
|
|
count = 0;
|
|
ebitmap_for_each_bit(&db->attr_type_map[i], node, bit) {
|
|
if (ebitmap_node_get_bit(node, bit))
|
|
count++;
|
|
}
|
|
if (count == 0) {
|
|
continue;
|
|
}
|
|
/* first create a new type_datum_t for the attribute,
|
|
* with the attribute's type_list consisting of types
|
|
* with this attribute */
|
|
/* Does not exist */
|
|
if (db->p_type_val_to_name[i] == NULL){
|
|
snprintf(buff, 9, "@ttr%04zd", i + 1);
|
|
tmp_name = strdup(buff);
|
|
if (!tmp_name) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
/* Already exists */
|
|
else
|
|
tmp_name = db->p_type_val_to_name[i];
|
|
|
|
tmp_type = calloc(1, sizeof(type_datum_t));
|
|
if (!tmp_type) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
tmp_type->primary = 1;
|
|
tmp_type->flavor = TYPE_ATTRIB;
|
|
tmp_type->s.value = i + 1;
|
|
if (ebitmap_cpy(&tmp_type->types, &db->attr_type_map[i])) {
|
|
error = ENOMEM;
|
|
goto err;
|
|
}
|
|
|
|
/* now go through each of the member types, and set
|
|
* their type_list bit to point back */
|
|
ebitmap_for_each_bit(&tmp_type->types, node, bit) {
|
|
if (ebitmap_node_get_bit(node, bit)) {
|
|
orig_type = db->type_val_to_struct[bit];
|
|
if (ebitmap_set_bit(&orig_type->types, tmp_type->s.value - 1, 1)) {
|
|
error = ENOMEM;
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
/* Does not exist - insert new */
|
|
if (db->p_type_val_to_name[i] == NULL){
|
|
retv = hashtab_insert(db->p_types.table, (hashtab_key_t) tmp_name, (hashtab_datum_t) tmp_type);
|
|
if (retv) {
|
|
if (retv == SEPOL_ENOMEM)
|
|
error = db->p_types.table ? ENOMEM : EINVAL;
|
|
else
|
|
error = EEXIST;
|
|
goto err;
|
|
}
|
|
}
|
|
/* Already exists - replace old */
|
|
else {
|
|
retv = hashtab_replace(db->p_types.table, (hashtab_key_t) tmp_name, (hashtab_datum_t) tmp_type, NULL, NULL);
|
|
if (retv) {
|
|
if (retv == SEPOL_ENOMEM)
|
|
error = db->p_types.table ? ENOMEM : EINVAL;
|
|
else
|
|
error = EEXIST;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
db->p_type_val_to_name[i] = tmp_name;
|
|
db->type_val_to_struct[i] = tmp_type;
|
|
|
|
/* memory now owned by symtab do not free */
|
|
tmp_name = NULL;
|
|
tmp_type = NULL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
err:
|
|
free(tmp_name);
|
|
type_datum_destroy(tmp_type);
|
|
free(tmp_type);
|
|
ERR(policy, "%s", strerror(error));
|
|
errno = error;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
/**
|
|
* Builds data for empty attributes and inserts them into the policydb.
|
|
* This function modifies the policydb. Names created for the attributes
|
|
* are of the form @ttr<value> where value is the value of the attribute
|
|
* as a four digit number (prepended with 0's as needed).
|
|
* @param policy The policy to which to add type data for attributes.
|
|
* This policy will be altered by this function.
|
|
* @return Returns 0 on success and < 0 on failure; if the call fails,
|
|
* errno will be set. On failure, the policy state may be inconsistent
|
|
* especially in the case where the hashtab functions return the error.
|
|
*/
|
|
static int qpol_policy_fill_attr_holes(qpol_policy_t * policy)
|
|
{
|
|
policydb_t *db = NULL;
|
|
char *tmp_name = NULL, buff[10];
|
|
int error = 0, retv = 0;
|
|
ebitmap_t tmp_bmap = { NULL, 0 };
|
|
type_datum_t *tmp_type = NULL;
|
|
size_t i;
|
|
|
|
if (policy == NULL) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
db = &policy->p->p;
|
|
|
|
memset(&buff, 0, 10 * sizeof(char));
|
|
|
|
for (i = 0; i < db->p_types.nprim; i++) {
|
|
if (db->type_val_to_struct[i])
|
|
continue;
|
|
snprintf(buff, 9, "@ttr%04zd", i + 1);
|
|
tmp_name = strdup(buff);
|
|
if (!tmp_name) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
tmp_type = calloc(1, sizeof(type_datum_t));
|
|
if (!tmp_type) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
tmp_type->primary = 1;
|
|
tmp_type->flavor = TYPE_ATTRIB;
|
|
tmp_type->s.value = i + 1;
|
|
tmp_type->types = tmp_bmap;
|
|
|
|
retv = hashtab_insert(db->p_types.table, (hashtab_key_t) tmp_name, (hashtab_datum_t) tmp_type);
|
|
if (retv) {
|
|
if (retv == SEPOL_ENOMEM)
|
|
error = db->p_types.table ? ENOMEM : EINVAL;
|
|
else
|
|
error = EEXIST;
|
|
goto err;
|
|
}
|
|
db->p_type_val_to_name[i] = tmp_name;
|
|
db->type_val_to_struct[i] = tmp_type;
|
|
|
|
/* memory now owned by symtab do not free */
|
|
tmp_name = NULL;
|
|
tmp_type = NULL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
err:
|
|
free(tmp_type);
|
|
free(tmp_name);
|
|
ERR(policy, "%s", strerror(error));
|
|
errno = error;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
static const char *const sidnames[] = {
|
|
"undefined",
|
|
"kernel",
|
|
"security",
|
|
"unlabeled",
|
|
"fs",
|
|
"file",
|
|
"file_labels",
|
|
"init",
|
|
"any_socket",
|
|
"port",
|
|
"netif",
|
|
"netmsg",
|
|
"node",
|
|
"igmp_packet",
|
|
"icmp_socket",
|
|
"tcp_socket",
|
|
"sysctl_modprobe",
|
|
"sysctl",
|
|
"sysctl_fs",
|
|
"sysctl_kernel",
|
|
"sysctl_net",
|
|
"sysctl_net_unix",
|
|
"sysctl_vm",
|
|
"sysctl_dev",
|
|
"kmod",
|
|
"policy",
|
|
"scmp_packet",
|
|
"devnull"
|
|
};
|
|
|
|
/**
|
|
* Uses names from flask to fill in the isid names which are not normally
|
|
* saved. This function modified the policydb.
|
|
* @param policy Policy to which to add sid names.
|
|
* This policy will be altered by this function.
|
|
* @return 0 on success and < 0 on failure; if the call fails,
|
|
* errno will be set. On failure, the policy state may be inconsistent.
|
|
*/
|
|
static int qpol_policy_add_isid_names(qpol_policy_t * policy)
|
|
{
|
|
policydb_t *db = NULL;
|
|
ocontext_t *sid = NULL;
|
|
uint32_t val = 0;
|
|
int error = 0;
|
|
|
|
if (policy == NULL) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
db = &policy->p->p;
|
|
|
|
for (sid = db->ocontexts[OCON_ISID]; sid; sid = sid->next) {
|
|
val = (uint32_t) sid->sid[0];
|
|
if (val > SECINITSID_NUM)
|
|
val = 0;
|
|
|
|
if (!sid->u.name) {
|
|
sid->u.name = strdup(sidnames[val]);
|
|
if (!sid->u.name) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
errno = error;
|
|
return STATUS_ERR;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int extend_assign_role_to_user(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args)
|
|
{
|
|
user_datum_t *user = (user_datum_t *) d;
|
|
uint32_t *value = (uint32_t *) args;
|
|
if (ebitmap_set_bit(&user->roles.roles, *value - 1, 1)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Modify the special role 'object_r' by assigning it to all users,
|
|
* and all types to object_r. This function modifies the policydb.
|
|
* @param policy Policy containing object_r. This policy will be
|
|
* altered by this function.
|
|
* @return 0 on success and < 0 on failure; if the call fails, errno
|
|
* will be set. On failure, the policy state may be inconsistent.
|
|
*/
|
|
static int qpol_policy_add_object_r(qpol_policy_t * policy)
|
|
{
|
|
policydb_t *db = NULL;
|
|
int error = 0;
|
|
|
|
if (policy == NULL) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
db = &policy->p->p;
|
|
|
|
hashtab_datum_t datum = hashtab_search(db->p_roles.table, (hashtab_key_t)OBJECT_R);
|
|
if (datum == NULL) {
|
|
ERR(policy, "%s", OBJECT_R " not found in policy!");
|
|
errno = EIO;
|
|
assert(0);
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
role_datum_t *role = (role_datum_t *) datum;
|
|
|
|
uint32_t value = role->s.value;
|
|
|
|
if (hashtab_map(db->p_users.table, extend_assign_role_to_user, &value) < 0) {
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
qpol_iterator_t *iter;
|
|
if (qpol_policy_get_type_iter(policy, &iter) < 0) {
|
|
return STATUS_ERR;
|
|
}
|
|
for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
|
|
const qpol_type_t *type;
|
|
unsigned char isattr, isalias;
|
|
if (qpol_iterator_get_item(iter, (void **)&type) < 0 ||
|
|
qpol_type_get_isattr(policy, type, &isattr) < 0 || qpol_type_get_isalias(policy, type, &isalias) < 0) {
|
|
error = errno;
|
|
qpol_iterator_destroy(&iter);
|
|
errno = error;
|
|
return STATUS_ERR;
|
|
}
|
|
if (isattr || isalias) {
|
|
continue;
|
|
}
|
|
if (qpol_type_get_value(policy, type, &value) < 0) {
|
|
error = errno;
|
|
qpol_iterator_destroy(&iter);
|
|
errno = error;
|
|
return STATUS_ERR;
|
|
}
|
|
if (ebitmap_set_bit(&role->types.types, value - 1, 1)) {
|
|
error = errno;
|
|
qpol_iterator_destroy(&iter);
|
|
errno = error;
|
|
return STATUS_ERR;
|
|
}
|
|
}
|
|
qpol_iterator_destroy(&iter);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* If the given policy's version is higher than the running system's
|
|
* version, then mark it as different. In a future version of
|
|
* libqpol, accessors will return data as if the policy were really
|
|
* the new version rather than what it actually is.
|
|
*/
|
|
static int qpol_policy_match_system(qpol_policy_t * policy)
|
|
{
|
|
int kernvers = security_policyvers();
|
|
unsigned int currentvers = policy->p->p.policyvers;
|
|
int error;
|
|
if (kernvers < 0) {
|
|
error = errno;
|
|
ERR(policy, "%s", "Could not determine running system's policy version.");
|
|
errno = error;
|
|
return -1;
|
|
}
|
|
if (currentvers > (unsigned)kernvers) {
|
|
if (sepol_policydb_set_vers(policy->p, kernvers)) {
|
|
error = errno;
|
|
ERR(policy, "Could not downgrade policy to version %d.", kernvers);
|
|
errno = error;
|
|
return -1;
|
|
}
|
|
WARN(policy, "Policy would be downgraded from version %d to %d.", currentvers, kernvers);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Walks the conditional list and adds links for reverse look up from
|
|
* a te/av rule to the conditional from which it came.
|
|
* @param policy The policy to which to add conditional trace backs.
|
|
* This policy will be altered by this function.
|
|
* @return 0 on success and < 0 on failure; if the call fails,
|
|
* errno will be set. On failure, the policy state may be inconsistent.
|
|
*/
|
|
static int qpol_policy_add_cond_rule_traceback(qpol_policy_t * policy)
|
|
{
|
|
policydb_t *db = NULL;
|
|
cond_node_t *cond = NULL;
|
|
cond_av_list_t *list_ptr = NULL;
|
|
qpol_iterator_t *iter = NULL;
|
|
avtab_ptr_t rule = NULL;
|
|
int error = 0;
|
|
uint32_t rules = 0;
|
|
|
|
INFO(policy, "%s", "Building conditional rules tables. (Step 5 of 5)");
|
|
if (!policy) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
db = &policy->p->p;
|
|
|
|
rules = (QPOL_RULE_ALLOW | QPOL_RULE_AUDITALLOW | QPOL_RULE_DONTAUDIT);
|
|
if (!(policy->options & QPOL_POLICY_OPTION_NO_NEVERALLOWS))
|
|
rules |= QPOL_RULE_NEVERALLOW;
|
|
|
|
/* mark all unconditional rules as enabled */
|
|
if (qpol_policy_get_avrule_iter(policy, rules, &iter))
|
|
return STATUS_ERR;
|
|
for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
|
|
if (qpol_iterator_get_item(iter, (void **)&rule)) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
errno = error;
|
|
return STATUS_ERR;
|
|
}
|
|
rule->parse_context = NULL;
|
|
rule->merged = QPOL_COND_RULE_ENABLED;
|
|
}
|
|
qpol_iterator_destroy(&iter);
|
|
if (qpol_policy_get_terule_iter(policy, (QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER), &iter))
|
|
return STATUS_ERR;
|
|
for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
|
|
if (qpol_iterator_get_item(iter, (void **)&rule)) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
errno = error;
|
|
return STATUS_ERR;
|
|
}
|
|
rule->parse_context = NULL;
|
|
rule->merged = QPOL_COND_RULE_ENABLED;
|
|
}
|
|
qpol_iterator_destroy(&iter);
|
|
|
|
for (cond = db->cond_list; cond; cond = cond->next) {
|
|
/* evaluate cond */
|
|
cond->cur_state = cond_evaluate_expr(db, cond->expr);
|
|
if (cond->cur_state < 0) {
|
|
ERR(policy, "Error evaluating conditional: %s", strerror(EILSEQ));
|
|
errno = EILSEQ;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
/* walk true list */
|
|
for (list_ptr = cond->true_list; list_ptr; list_ptr = list_ptr->next) {
|
|
/* field not used after parse, now stores cond */
|
|
list_ptr->node->parse_context = (void *)cond;
|
|
/* field not used (except by write),
|
|
* now storing list and enabled flags */
|
|
list_ptr->node->merged = QPOL_COND_RULE_LIST;
|
|
if (cond->cur_state)
|
|
list_ptr->node->merged |= QPOL_COND_RULE_ENABLED;
|
|
}
|
|
|
|
/* walk false list */
|
|
for (list_ptr = cond->false_list; list_ptr; list_ptr = list_ptr->next) {
|
|
/* field not used after parse, now stores cond */
|
|
list_ptr->node->parse_context = (void *)cond;
|
|
/* field not used (except by write),
|
|
* now storing list and enabled flags */
|
|
list_ptr->node->merged = 0; /* i.e. !QPOL_COND_RULE_LIST */
|
|
if (!cond->cur_state)
|
|
list_ptr->node->merged |= QPOL_COND_RULE_ENABLED;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Free all allocated memory used by a qpol_syn_rule.
|
|
* @param r Reference pointer to the rule to destroy.
|
|
*/
|
|
static void qpol_syn_rule_destroy(struct qpol_syn_rule **r)
|
|
{
|
|
if (!r || !(*r))
|
|
return;
|
|
|
|
free(*r);
|
|
*r = NULL;
|
|
}
|
|
|
|
/**
|
|
* Free all memory used by a syn rule list.
|
|
* @param list Reference pointer to the head node of
|
|
* the syn rule list to destroy. All nodes in the list will
|
|
* be destroyed.
|
|
*/
|
|
static void qpol_syn_rule_list_destroy(qpol_syn_rule_list_t ** list)
|
|
{
|
|
qpol_syn_rule_list_t *cur = NULL, *next = NULL;
|
|
|
|
if (!list || !(*list))
|
|
return;
|
|
|
|
for (cur = *list; cur; cur = next) {
|
|
next = cur->next;
|
|
free(cur);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Free all memory used by a syn rule node in the rule table.
|
|
* @param node Reference pointer to the first node in the chain.
|
|
* All nodes in the chain will be destroyed.
|
|
*/
|
|
static void qpol_syn_rule_node_destroy(qpol_syn_rule_node_t ** node)
|
|
{
|
|
qpol_syn_rule_node_t *cur = NULL, *next = NULL;
|
|
|
|
if (!node || !(*node))
|
|
return;
|
|
|
|
for (cur = *node; cur; cur = next) {
|
|
next = cur->next;
|
|
qpol_syn_rule_list_destroy(&cur->rules);
|
|
free(cur);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Free all memory used by the syntactic rule table.
|
|
* @param t Reference pointer to the table to destroy.
|
|
*/
|
|
static void qpol_syn_rule_table_destroy(qpol_syn_rule_table_t ** t)
|
|
{
|
|
size_t i = 0;
|
|
|
|
if (!t || !(*t))
|
|
return;
|
|
|
|
for (i = 0; i < QPOL_SYN_RULE_TABLE_SIZE; i++)
|
|
qpol_syn_rule_node_destroy(&((*t)->buckets[i]));
|
|
|
|
free((*t)->buckets);
|
|
free(*t);
|
|
*t = NULL;
|
|
}
|
|
|
|
/**
|
|
* Find the node in the syntactic rule hash table corresponding to a key.
|
|
* @param table The table to search.
|
|
* @param key The key for which to search.
|
|
* @return a valid qpol_syn_rule_node_t pointer on success or NULL on failure.
|
|
*/
|
|
static qpol_syn_rule_node_t *qpol_syn_rule_table_find_node_by_key(const qpol_syn_rule_table_t * table,
|
|
const qpol_syn_rule_key_t * key)
|
|
{
|
|
qpol_syn_rule_node_t *node = NULL;
|
|
|
|
for (node = table->buckets[QPOL_SYN_RULE_TABLE_HASH(key)]; node; node = node->next) {
|
|
if ((node->key.rule_type & key->rule_type) &&
|
|
(node->key.source_val == key->source_val) &&
|
|
(node->key.target_val == key->target_val) &&
|
|
(node->key.class_val == key->class_val) && (node->key.cond == key->cond))
|
|
return node;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Given a syn rule key and a syn rule, adds the key/rule pair to the
|
|
* syn rule table. Note that this function takes ownership of the
|
|
* key.
|
|
*
|
|
* @param policy Policy associated with the rule.
|
|
* @param table The table to which to add the rule.
|
|
* @param key Hashtable key for rule lookup.
|
|
* @param rule The rule to add.
|
|
* @return 0 on success and < 0 on failure; if the call fails,
|
|
* errno will be set and the table may be in an inconsistent state.
|
|
*/
|
|
static int qpol_syn_rule_table_insert_entry(qpol_policy_t * policy,
|
|
qpol_syn_rule_table_t * table, qpol_syn_rule_key_t * key, struct qpol_syn_rule *rule)
|
|
{
|
|
int error = 0;
|
|
qpol_syn_rule_node_t *table_node = NULL;
|
|
qpol_syn_rule_list_t *list_entry = NULL;
|
|
|
|
if (!(list_entry = malloc(sizeof(qpol_syn_rule_list_t)))) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
return -1;
|
|
}
|
|
list_entry->rule = rule;
|
|
|
|
table_node = qpol_syn_rule_table_find_node_by_key(table, key);
|
|
if (table_node) {
|
|
list_entry->next = table_node->rules;
|
|
table_node->rules = list_entry;
|
|
} else {
|
|
list_entry->next = NULL;
|
|
if (!(table_node = malloc(sizeof(qpol_syn_rule_node_t)))) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
free(list_entry);
|
|
return -1;
|
|
}
|
|
table_node->key = *key;
|
|
table_node->rules = list_entry;
|
|
size_t hash = QPOL_SYN_RULE_TABLE_HASH(key);
|
|
table_node->next = table->buckets[hash];
|
|
table->buckets[hash] = table_node;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Add a syntactic rule (sepol's avrule_t) to the syntactic rule table.
|
|
* @param policy Policy associated with the rule.
|
|
* @param table The table to which to add the rule.
|
|
* @param rule The rule to add.
|
|
* @param cond The conditional associated with the rule (NULL if
|
|
* unconditional). with the rule (needed for conditional tracking).
|
|
* @param branch If the rule is conditional, then 0 if in the true
|
|
* branch, 1 if in else.
|
|
* @return 0 on success and < 0 on failure; if the call fails,
|
|
* errno will be set and the table may be in an inconsistent state.
|
|
*/
|
|
static int qpol_syn_rule_table_insert_sepol_avrule(qpol_policy_t * policy, qpol_syn_rule_table_t * table, avrule_t * rule,
|
|
cond_node_t * cond, int branch)
|
|
{
|
|
int error = 0;
|
|
qpol_syn_rule_key_t key = { 0, 0, 0, 0, NULL };
|
|
struct qpol_syn_rule *new_rule = NULL;
|
|
ebitmap_t source_types, source_types2, target_types, target_types2;
|
|
ebitmap_node_t *snode = NULL, *tnode = NULL;
|
|
unsigned int i, j;
|
|
class_perm_node_t *class_node = NULL;
|
|
|
|
if (!(new_rule = malloc(sizeof(struct qpol_syn_rule)))) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
goto err;
|
|
}
|
|
new_rule->rule = rule;
|
|
new_rule->cond = cond;
|
|
new_rule->cond_branch = branch;
|
|
|
|
policy->ext->syn_rule_master_list[policy->ext->master_list_sz] = new_rule;
|
|
policy->ext->master_list_sz++;
|
|
|
|
if (type_set_expand(&rule->stypes, &source_types, &policy->p->p, 0) ||
|
|
type_set_expand(&rule->stypes, &source_types2, &policy->p->p, 1)) {
|
|
ERR(policy, "%s", strerror(ENOMEM));
|
|
error = ENOMEM;
|
|
goto err;
|
|
}
|
|
if (type_set_expand(&rule->ttypes, &target_types, &policy->p->p, 0) ||
|
|
type_set_expand(&rule->ttypes, &target_types2, &policy->p->p, 1)) {
|
|
ERR(policy, "%s", strerror(ENOMEM));
|
|
error = ENOMEM;
|
|
goto err;
|
|
}
|
|
if (ebitmap_union(&source_types, &source_types2) || ebitmap_union(&target_types, &target_types2)) {
|
|
ERR(policy, "%s", strerror(ENOMEM));
|
|
error = ENOMEM;
|
|
goto err;
|
|
}
|
|
ebitmap_for_each_bit(&source_types, snode, i) {
|
|
if (!ebitmap_get_bit(&source_types, i))
|
|
continue;
|
|
if (rule->flags & RULE_SELF) {
|
|
for (class_node = rule->perms; class_node; class_node = class_node->next) {
|
|
key.rule_type = rule->specified;
|
|
key.source_val = key.target_val = i + 1;
|
|
key.class_val = class_node->class;
|
|
key.cond = cond;
|
|
if (qpol_syn_rule_table_insert_entry(policy, table, &key, new_rule))
|
|
goto err;
|
|
}
|
|
}
|
|
ebitmap_for_each_bit(&target_types, tnode, j) {
|
|
if (!ebitmap_get_bit(&target_types, j))
|
|
continue;
|
|
for (class_node = rule->perms; class_node; class_node = class_node->next) {
|
|
key.rule_type = rule->specified;
|
|
key.source_val = i + 1;
|
|
key.target_val = j + 1;
|
|
key.class_val = class_node->class;
|
|
key.cond = cond;
|
|
if (qpol_syn_rule_table_insert_entry(policy, table, &key, new_rule))
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
|
|
ebitmap_destroy(&source_types);
|
|
ebitmap_destroy(&source_types2);
|
|
ebitmap_destroy(&target_types);
|
|
ebitmap_destroy(&target_types2);
|
|
return error;
|
|
|
|
err:
|
|
ebitmap_destroy(&source_types);
|
|
ebitmap_destroy(&source_types2);
|
|
ebitmap_destroy(&target_types);
|
|
ebitmap_destroy(&target_types2);
|
|
return -1;
|
|
}
|
|
|
|
int qpol_policy_build_syn_rule_table(qpol_policy_t * policy)
|
|
{
|
|
int error = 0, created = 0;
|
|
avrule_block_t *cur_block = NULL;
|
|
avrule_decl_t *decl = NULL;
|
|
avrule_t *cur_rule = NULL;
|
|
cond_node_t *cur_cond = NULL, *remapped_cond;
|
|
|
|
if (!policy) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
if (!policy->ext) {
|
|
policy->ext = calloc(1, sizeof(qpol_extended_image_t));
|
|
if (!policy->ext) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
if (policy->ext->syn_rule_table)
|
|
return 0; /* already built */
|
|
|
|
policy->ext->syn_rule_table = calloc(1, sizeof(qpol_syn_rule_table_t));
|
|
if (!policy->ext->syn_rule_table) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
goto err;
|
|
}
|
|
policy->ext->syn_rule_table->buckets = calloc(QPOL_SYN_RULE_TABLE_SIZE, sizeof(qpol_syn_rule_node_t *));
|
|
if (!policy->ext->syn_rule_table->buckets) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
goto err;
|
|
}
|
|
|
|
policy->ext->master_list_sz = 0;
|
|
for (cur_block = policy->p->p.global; cur_block; cur_block = cur_block->next) {
|
|
decl = cur_block->enabled;
|
|
if (!decl)
|
|
continue;
|
|
|
|
for (cur_rule = decl->avrules; cur_rule; cur_rule = cur_rule->next) {
|
|
policy->ext->master_list_sz++;
|
|
}
|
|
for (cur_cond = decl->cond_list; cur_cond; cur_cond = cur_cond->next) {
|
|
for (cur_rule = cur_cond->avtrue_list; cur_rule; cur_rule = cur_rule->next) {
|
|
policy->ext->master_list_sz++;
|
|
}
|
|
for (cur_rule = cur_cond->avfalse_list; cur_rule; cur_rule = cur_rule->next) {
|
|
policy->ext->master_list_sz++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (policy->ext->master_list_sz == 0) {
|
|
policy->ext->syn_rule_master_list = NULL;
|
|
return 0; /* policy is not a source policy */
|
|
}
|
|
|
|
INFO(policy, "%s", "Building syntactic rules tables.");
|
|
|
|
policy->ext->syn_rule_master_list = calloc(policy->ext->master_list_sz, sizeof(struct qpol_syn_rule *));
|
|
if (!policy->ext->syn_rule_master_list) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
goto err;
|
|
}
|
|
|
|
/* reset size as it will represent the current number of elements inserted */
|
|
policy->ext->master_list_sz = 0;
|
|
|
|
for (cur_block = policy->p->p.global; cur_block; cur_block = cur_block->next) {
|
|
decl = cur_block->enabled;
|
|
if (!decl)
|
|
continue;
|
|
|
|
for (cur_rule = decl->avrules; cur_rule; cur_rule = cur_rule->next) {
|
|
if (qpol_syn_rule_table_insert_sepol_avrule(policy, policy->ext->syn_rule_table, cur_rule, NULL, 0)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
}
|
|
for (cur_cond = decl->cond_list; cur_cond; cur_cond = cur_cond->next) {
|
|
/* convert the cond within an avrule_decl to
|
|
* the expanded cond */
|
|
remapped_cond = cond_node_find(&policy->p->p, cur_cond, policy->p->p.cond_list, &created);
|
|
if (created || !remapped_cond) {
|
|
cond_node_destroy(remapped_cond);
|
|
error = EIO;
|
|
ERR(policy, "%s", "Inconsistent conditional records");
|
|
assert(0);
|
|
goto err;
|
|
}
|
|
for (cur_rule = cur_cond->avtrue_list; cur_rule; cur_rule = cur_rule->next) {
|
|
if (qpol_syn_rule_table_insert_sepol_avrule
|
|
(policy, policy->ext->syn_rule_table, cur_rule, remapped_cond, 0)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
}
|
|
for (cur_rule = cur_cond->avfalse_list; cur_rule; cur_rule = cur_rule->next) {
|
|
if (qpol_syn_rule_table_insert_sepol_avrule
|
|
(policy, policy->ext->syn_rule_table, cur_rule, remapped_cond, 1)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef SETOOLS_DEBUG
|
|
/*
|
|
* Debugging code to measure the how well the syntactic rules
|
|
* are being hashed. Calculate the min, max, and std
|
|
* deviation.
|
|
*/
|
|
size_t bucket;
|
|
float o2 = 0.0f;
|
|
long total_entries = 0;
|
|
for (bucket = 0; bucket < QPOL_SYN_RULE_TABLE_SIZE; bucket++) {
|
|
qpol_syn_rule_node_t *n = policy->ext->syn_rule_table->buckets[bucket];
|
|
while (n != NULL) {
|
|
total_entries++;
|
|
n = n->next;
|
|
}
|
|
}
|
|
float expected_value = total_entries * 1.0f / QPOL_SYN_RULE_TABLE_SIZE;
|
|
size_t min_items = total_entries;
|
|
size_t max_items = 0;
|
|
for (bucket = 0; bucket < QPOL_SYN_RULE_TABLE_SIZE; bucket++) {
|
|
size_t num_items = 0;
|
|
qpol_syn_rule_node_t *n = policy->ext->syn_rule_table->buckets[bucket];
|
|
while (n != NULL) {
|
|
num_items++;
|
|
n = n->next;
|
|
}
|
|
if (num_items > max_items) {
|
|
max_items = num_items;
|
|
}
|
|
if (num_items < min_items) {
|
|
min_items = num_items;
|
|
}
|
|
o2 += (num_items - expected_value) * (num_items - expected_value);
|
|
}
|
|
float stddev = sqrtf(o2 / (QPOL_SYN_RULE_TABLE_SIZE - 1));
|
|
fprintf(stderr, "libqpol synrule table %d bits: total entries %lu, expected %g\n", QPOL_SYN_RULE_TABLE_BITS, total_entries,
|
|
expected_value);
|
|
fprintf(stderr, " min %zd, max %zd, stddev %g\n", min_items, max_items, stddev);
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
err:
|
|
if (policy->ext)
|
|
qpol_syn_rule_table_destroy(&policy->ext->syn_rule_table);
|
|
errno = error;
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Free all memory used by a qpol extended image and set it to NULL.
|
|
* @param ext The extended image to destroy.
|
|
*/
|
|
void qpol_extended_image_destroy(qpol_extended_image_t ** ext)
|
|
{
|
|
size_t i = 0;
|
|
|
|
if (!ext || !(*ext))
|
|
return;
|
|
|
|
qpol_syn_rule_table_destroy(&((*ext)->syn_rule_table));
|
|
|
|
for (i = 0; i < (*ext)->master_list_sz; i++) {
|
|
qpol_syn_rule_destroy(&((*ext)->syn_rule_master_list[i]));
|
|
}
|
|
free((*ext)->syn_rule_master_list);
|
|
|
|
free(*ext);
|
|
*ext = NULL;
|
|
}
|
|
|
|
int policy_extend(qpol_policy_t * policy)
|
|
{
|
|
int retv, error;
|
|
policydb_t *db = NULL;
|
|
|
|
if (policy == NULL) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
db = &policy->p->p;
|
|
|
|
retv = qpol_policy_remove_bogus_aliases(policy);
|
|
if (retv) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
if (db->attr_type_map) {
|
|
retv = qpol_policy_build_attrs_from_map(policy);
|
|
if (retv) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
if (db->policy_type == POLICY_KERN) {
|
|
retv = qpol_policy_fill_attr_holes(policy);
|
|
if (retv) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
retv = qpol_policy_add_isid_names(policy);
|
|
if (retv) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
retv = qpol_policy_add_object_r(policy);
|
|
if (retv) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
|
|
if ((policy->options & QPOL_POLICY_OPTION_MATCH_SYSTEM) && qpol_policy_match_system(policy)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
|
|
if (policy->options & QPOL_POLICY_OPTION_NO_RULES)
|
|
return STATUS_SUCCESS;
|
|
|
|
retv = qpol_policy_add_cond_rule_traceback(policy);
|
|
if (retv) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
err:
|
|
/* no need to call ERR here as it will already have been called */
|
|
qpol_extended_image_destroy(&policy->ext);
|
|
errno = error;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
typedef struct syn_rule_state
|
|
{
|
|
qpol_syn_rule_node_t *node;
|
|
qpol_syn_rule_list_t *cur;
|
|
} syn_rule_state_t;
|
|
|
|
static int syn_rule_state_end(const qpol_iterator_t * iter)
|
|
{
|
|
syn_rule_state_t *srs = NULL;
|
|
|
|
if (!iter || !(srs = qpol_iterator_state(iter))) {
|
|
errno = EINVAL;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
return (srs->cur ? 0 : 1);
|
|
}
|
|
|
|
static void *syn_rule_state_get_cur(const qpol_iterator_t * iter)
|
|
{
|
|
syn_rule_state_t *srs = NULL;
|
|
|
|
if (!iter || !(srs = qpol_iterator_state(iter)) || qpol_iterator_end(iter)) {
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
return srs->cur->rule;
|
|
}
|
|
|
|
static int syn_rule_state_next(qpol_iterator_t * iter)
|
|
{
|
|
syn_rule_state_t *srs = NULL;
|
|
|
|
if (!iter || !(srs = qpol_iterator_state(iter))) {
|
|
errno = EINVAL;
|
|
return STATUS_ERR;
|
|
}
|
|
if (qpol_iterator_end(iter)) {
|
|
errno = ERANGE;
|
|
return STATUS_ERR;
|
|
}
|
|
|
|
srs->cur = srs->cur->next;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static size_t syn_rule_state_size(const qpol_iterator_t * iter)
|
|
{
|
|
size_t count = 0;
|
|
qpol_syn_rule_list_t *tmp = NULL;
|
|
syn_rule_state_t *srs = NULL;
|
|
|
|
if (!iter || !(srs = qpol_iterator_state(iter))) {
|
|
errno = EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
for (tmp = srs->node->rules; tmp; tmp = tmp->next)
|
|
count++;
|
|
|
|
return count;
|
|
}
|
|
|
|
int qpol_avrule_get_syn_avrule_iter(const qpol_policy_t * policy, const struct qpol_avrule *rule, qpol_iterator_t ** iter)
|
|
{
|
|
qpol_syn_rule_key_t *key = NULL;
|
|
const qpol_type_t *tmp_type;
|
|
const qpol_class_t *tmp_class;
|
|
const qpol_cond_t *tmp_cond;
|
|
syn_rule_state_t *srs = NULL;
|
|
uint32_t tmp_val;
|
|
int error = 0;
|
|
|
|
if (iter)
|
|
*iter = NULL;
|
|
|
|
if (!policy || !policy->ext || !rule || !iter) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
/* build key */
|
|
if (!(key = calloc(1, sizeof(qpol_syn_rule_key_t)))) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
goto err;
|
|
}
|
|
|
|
if (qpol_avrule_get_rule_type(policy, rule, &tmp_val)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->rule_type = (tmp_val == QPOL_RULE_DONTAUDIT ? (AVRULE_AUDITDENY | AVRULE_DONTAUDIT) : tmp_val);
|
|
|
|
if (qpol_avrule_get_source_type(policy, rule, &tmp_type)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
if (qpol_type_get_value(policy, tmp_type, &tmp_val)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->source_val = tmp_val;
|
|
|
|
if (qpol_avrule_get_target_type(policy, rule, &tmp_type)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
if (qpol_type_get_value(policy, tmp_type, &tmp_val)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->target_val = tmp_val;
|
|
|
|
if (qpol_avrule_get_object_class(policy, rule, &tmp_class)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
if (qpol_class_get_value(policy, tmp_class, &tmp_val)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->class_val = tmp_val;
|
|
|
|
if (qpol_avrule_get_cond(policy, rule, &tmp_cond)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->cond = (cond_node_t *) tmp_cond;
|
|
|
|
/* build state object */
|
|
if (!(srs = calloc(1, sizeof(syn_rule_state_t)))) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
goto err;
|
|
}
|
|
|
|
srs->node = qpol_syn_rule_table_find_node_by_key(policy->ext->syn_rule_table, key);
|
|
if (!srs->node) {
|
|
ERR(policy, "%s", "Unable to locate syntactic rules for semantic av rule");
|
|
errno = ENOENT;
|
|
goto err;
|
|
}
|
|
srs->cur = srs->node->rules;
|
|
|
|
if (qpol_iterator_create(policy, (void *)srs,
|
|
syn_rule_state_get_cur, syn_rule_state_next, syn_rule_state_end, syn_rule_state_size, free, iter))
|
|
{
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
|
|
free(key);
|
|
|
|
return 0;
|
|
|
|
err:
|
|
free(key);
|
|
free(srs);
|
|
errno = error;
|
|
return -1;
|
|
}
|
|
|
|
int qpol_terule_get_syn_terule_iter(const qpol_policy_t * policy, const struct qpol_terule *rule, qpol_iterator_t ** iter)
|
|
{
|
|
qpol_syn_rule_key_t *key = NULL;
|
|
const qpol_type_t *tmp_type;
|
|
const qpol_class_t *tmp_class;
|
|
const qpol_cond_t *tmp_cond;
|
|
syn_rule_state_t *srs = NULL;
|
|
uint32_t tmp_val;
|
|
int error = 0;
|
|
|
|
if (iter)
|
|
*iter = NULL;
|
|
|
|
if (!policy || !policy->ext || !rule || !iter) {
|
|
ERR(policy, "%s", strerror(EINVAL));
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
/* build key */
|
|
if (!(key = calloc(1, sizeof(qpol_syn_rule_key_t)))) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
goto err;
|
|
}
|
|
|
|
if (qpol_terule_get_rule_type(policy, rule, &tmp_val)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->rule_type = tmp_val;
|
|
|
|
if (qpol_terule_get_source_type(policy, rule, &tmp_type)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
if (qpol_type_get_value(policy, tmp_type, &tmp_val)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->source_val = tmp_val;
|
|
|
|
if (qpol_terule_get_target_type(policy, rule, &tmp_type)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
if (qpol_type_get_value(policy, tmp_type, &tmp_val)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->target_val = tmp_val;
|
|
|
|
if (qpol_terule_get_object_class(policy, rule, &tmp_class)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
if (qpol_class_get_value(policy, tmp_class, &tmp_val)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->class_val = tmp_val;
|
|
|
|
if (qpol_terule_get_cond(policy, rule, &tmp_cond)) {
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
key->cond = (cond_node_t *) tmp_cond;
|
|
|
|
/* build state object */
|
|
if (!(srs = calloc(1, sizeof(syn_rule_state_t)))) {
|
|
error = errno;
|
|
ERR(policy, "%s", strerror(error));
|
|
goto err;
|
|
}
|
|
|
|
srs->node = qpol_syn_rule_table_find_node_by_key(policy->ext->syn_rule_table, key);
|
|
if (!srs->node) {
|
|
ERR(policy, "%s", "Unable to locate syntactic rules for semantic te rule");
|
|
error = ENOENT;
|
|
goto err;
|
|
}
|
|
srs->cur = srs->node->rules;
|
|
|
|
if (qpol_iterator_create(policy, (void *)srs,
|
|
syn_rule_state_get_cur, syn_rule_state_next, syn_rule_state_end, syn_rule_state_size, free, iter))
|
|
{
|
|
error = errno;
|
|
goto err;
|
|
}
|
|
|
|
free(key);
|
|
|
|
return 0;
|
|
|
|
err:
|
|
free(key);
|
|
free(srs);
|
|
errno = error;
|
|
return -1;
|
|
}
|