hackedteam/core-android-native

View on GitHub
selinux_native/jni/libsepol/src/nodes.c

Summary

Maintainability
Test Coverage
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>

#include "debug.h"
#include "context.h"
#include "handle.h"
#include "log.h"

#include <sepol/policydb/policydb.h>
#include "node_internal.h"

/* Create a low level node structure from
 * a high level representation */
static int node_from_record(sepol_handle_t * handle,
                const policydb_t * policydb,
                ocontext_t ** node, const sepol_node_t * data)
{

    ocontext_t *tmp_node = NULL;
    context_struct_t *tmp_con = NULL;
    char *addr_buf = NULL, *mask_buf = NULL;

    tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t));
    if (!tmp_node)
        goto omem;

    size_t addr_bsize, mask_bsize;

    /* Address and netmask */
    if (sepol_node_get_addr_bytes(handle, data, &addr_buf, &addr_bsize) < 0)
        goto err;
    if (sepol_node_get_mask_bytes(handle, data, &mask_buf, &mask_bsize) < 0)
        goto err;

    int proto = sepol_node_get_proto(data);

    switch (proto) {
    case SEPOL_PROTO_IP4:
        memcpy(&tmp_node->u.node.addr, addr_buf, addr_bsize);
        memcpy(&tmp_node->u.node.mask, mask_buf, mask_bsize);
        break;
    case SEPOL_PROTO_IP6:
        memcpy(tmp_node->u.node6.addr, addr_buf, addr_bsize);
        memcpy(tmp_node->u.node6.mask, mask_buf, mask_bsize);
        break;
    default:
        LOGD( "unsupported protocol %u", proto);
        goto err;
    }
    free(addr_buf);
    free(mask_buf);
    addr_buf = NULL;
    mask_buf = NULL;

    /* Context */
    if (context_from_record(handle, policydb, &tmp_con,
                sepol_node_get_con(data)) < 0)
        goto err;
    context_cpy(&tmp_node->context[0], tmp_con);
    context_destroy(tmp_con);
    free(tmp_con);
    tmp_con = NULL;

    *node = tmp_node;
    return STATUS_SUCCESS;

      omem:
    LOGD( "out of memory");

      err:
    if (tmp_node != NULL) {
        context_destroy(&tmp_node->context[0]);
        free(tmp_node);
    }
    context_destroy(tmp_con);
    free(tmp_con);
    free(addr_buf);
    free(mask_buf);
    LOGD( "could not create node structure");
    return STATUS_ERR;
}

static int node_to_record(sepol_handle_t * handle,
              const policydb_t * policydb,
              ocontext_t * node, int proto, sepol_node_t ** record)
{

    context_struct_t *con = &node->context[0];

    sepol_context_t *tmp_con = NULL;
    sepol_node_t *tmp_record = NULL;

    if (sepol_node_create(handle, &tmp_record) < 0)
        goto err;

    sepol_node_set_proto(tmp_record, proto);

    switch (proto) {

    case SEPOL_PROTO_IP4:
        if (sepol_node_set_addr_bytes(handle, tmp_record,
                          (const char *)&node->u.node.addr,
                          4) < 0)
            goto err;

        if (sepol_node_set_mask_bytes(handle, tmp_record,
                          (const char *)&node->u.node.mask,
                          4) < 0)
            goto err;
        break;

    case SEPOL_PROTO_IP6:
        if (sepol_node_set_addr_bytes(handle, tmp_record,
                          (const char *)&node->u.node6.addr,
                          16) < 0)
            goto err;

        if (sepol_node_set_mask_bytes(handle, tmp_record,
                          (const char *)&node->u.node6.mask,
                          16) < 0)
            goto err;
        break;

    default:
        LOGD( "unsupported protocol %u", proto);
        goto err;
    }

    if (context_to_record(handle, policydb, con, &tmp_con) < 0)
        goto err;

    if (sepol_node_set_con(handle, tmp_record, tmp_con) < 0)
        goto err;

    sepol_context_free(tmp_con);
    *record = tmp_record;
    return STATUS_SUCCESS;

      err:
    LOGD( "could not convert node to record");
    sepol_context_free(tmp_con);
    sepol_node_free(tmp_record);
    return STATUS_ERR;
}

/* Return the number of nodes */
extern int sepol_node_count(sepol_handle_t * handle __attribute__ ((unused)),
                const sepol_policydb_t * p, unsigned int *response)
{

    unsigned int count = 0;
    ocontext_t *c, *head;
    const policydb_t *policydb = &p->p;

    head = policydb->ocontexts[OCON_NODE];
    for (c = head; c != NULL; c = c->next)
        count++;

    head = policydb->ocontexts[OCON_NODE6];
    for (c = head; c != NULL; c = c->next)
        count++;

    *response = count;

    handle = NULL;
    return STATUS_SUCCESS;
}

/* Check if a node exists */
int sepol_node_exists(sepol_handle_t * handle,
              const sepol_policydb_t * p,
              const sepol_node_key_t * key, int *response)
{

    const policydb_t *policydb = &p->p;
    ocontext_t *c, *head;

    int proto;
    const char *addr, *mask;
    sepol_node_key_unpack(key, &addr, &mask, &proto);

    switch (proto) {

    case SEPOL_PROTO_IP4:
        {
            head = policydb->ocontexts[OCON_NODE];
            for (c = head; c; c = c->next) {
                unsigned int *addr2 = &c->u.node.addr;
                unsigned int *mask2 = &c->u.node.mask;

                if (!memcmp(addr, addr2, 4) &&
                    !memcmp(mask, mask2, 4)) {

                    *response = 1;
                    return STATUS_SUCCESS;
                }
            }
            break;
        }
    case SEPOL_PROTO_IP6:
        {
            head = policydb->ocontexts[OCON_NODE6];
            for (c = head; c; c = c->next) {
                unsigned int *addr2 = c->u.node6.addr;
                unsigned int *mask2 = c->u.node6.mask;

                if (!memcmp(addr, addr2, 16) &&
                    !memcmp(mask, mask2, 16)) {
                    *response = 1;
                    return STATUS_SUCCESS;
                }
            }
            break;
        }
    default:
        LOGD( "unsupported protocol %u", proto);
        goto err;
    }

    *response = 0;
    return STATUS_SUCCESS;

      err:
    LOGD( "could not check if node %s/%s (%s) exists",
        addr, mask, sepol_node_get_proto_str(proto));
    return STATUS_ERR;
}

/* Query a node */
int sepol_node_query(sepol_handle_t * handle,
             const sepol_policydb_t * p,
             const sepol_node_key_t * key, sepol_node_t ** response)
{

    const policydb_t *policydb = &p->p;
    ocontext_t *c, *head;

    int proto;
    const char *addr, *mask;
    sepol_node_key_unpack(key, &addr, &mask, &proto);

    switch (proto) {

    case SEPOL_PROTO_IP4:
        {
            head = policydb->ocontexts[OCON_NODE];
            for (c = head; c; c = c->next) {
                unsigned int *addr2 = &c->u.node.addr;
                unsigned int *mask2 = &c->u.node.mask;

                if (!memcmp(addr, addr2, 4) &&
                    !memcmp(mask, mask2, 4)) {

                    if (node_to_record(handle, policydb,
                               c, SEPOL_PROTO_IP4,
                               response) < 0)
                        goto err;
                    return STATUS_SUCCESS;
                }
            }
            break;
        }
    case SEPOL_PROTO_IP6:
        {
            head = policydb->ocontexts[OCON_NODE6];
            for (c = head; c; c = c->next) {
                unsigned int *addr2 = c->u.node6.addr;
                unsigned int *mask2 = c->u.node6.mask;

                if (!memcmp(addr, addr2, 16) &&
                    !memcmp(mask, mask2, 16)) {

                    if (node_to_record(handle, policydb,
                               c, SEPOL_PROTO_IP6,
                               response) < 0)
                        goto err;
                }
            }
            break;
        }
    default:
        LOGD( "unsupported protocol %u", proto);
        goto err;
    }
    *response = NULL;
    return STATUS_SUCCESS;

      err:
    LOGD( "could not query node %s/%s (%s)",
        addr, mask, sepol_node_get_proto_str(proto));
    return STATUS_ERR;

}

/* Load a node into policy */
int sepol_node_modify(sepol_handle_t * handle,
              sepol_policydb_t * p,
              const sepol_node_key_t * key, const sepol_node_t * data)
{

    policydb_t *policydb = &p->p;
    ocontext_t *node = NULL;

    int proto;
    const char *addr, *mask;

    sepol_node_key_unpack(key, &addr, &mask, &proto);

    if (node_from_record(handle, policydb, &node, data) < 0)
        goto err;

    switch (proto) {

    case SEPOL_PROTO_IP4:
        {
            /* Attach to context list */
            node->next = policydb->ocontexts[OCON_NODE];
            policydb->ocontexts[OCON_NODE] = node;
            break;
        }
    case SEPOL_PROTO_IP6:
        {
            /* Attach to context list */
            node->next = policydb->ocontexts[OCON_NODE6];
            policydb->ocontexts[OCON_NODE6] = node;
            break;
        }
    default:
        LOGD( "unsupported protocol %u", proto);
        goto err;
    }

    return STATUS_SUCCESS;

      err:
    LOGD( "could not load node %s/%s (%s)",
        addr, mask, sepol_node_get_proto_str(proto));
    if (node != NULL) {
        context_destroy(&node->context[0]);
        free(node);
    }
    return STATUS_ERR;
}

int sepol_node_iterate(sepol_handle_t * handle,
               const sepol_policydb_t * p,
               int (*fn) (const sepol_node_t * node,
                  void *fn_arg), void *arg)
{

    const policydb_t *policydb = &p->p;
    ocontext_t *c, *head;
    sepol_node_t *node = NULL;
    int status;

    head = policydb->ocontexts[OCON_NODE];
    for (c = head; c; c = c->next) {
        if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP4, &node)
            < 0)
            goto err;

        /* Invoke handler */
        status = fn(node, arg);
        if (status < 0)
            goto err;

        sepol_node_free(node);
        node = NULL;

        /* Handler requested exit */
        if (status > 0)
            break;
    }

    head = policydb->ocontexts[OCON_NODE6];
    for (c = head; c; c = c->next) {
        if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP6, &node)
            < 0)
            goto err;

        /* Invoke handler */
        status = fn(node, arg);
        if (status < 0)
            goto err;

        sepol_node_free(node);
        node = NULL;

        /* Handler requested exit */
        if (status > 0)
            break;
    }

    return STATUS_SUCCESS;

      err:
    LOGD( "could not iterate over nodes");
    sepol_node_free(node);
    return STATUS_ERR;
}