hackedteam/core-android-native

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

Summary

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

#include "node_internal.h"
#include "context_internal.h"
#include "debug.h"
#include "log.h"

struct sepol_node {

    /* Network address and mask */
    char *addr;
    size_t addr_sz;

    char *mask;
    size_t mask_sz;

    /* Protocol */
    int proto;

    /* Context */
    sepol_context_t *con;
};

struct sepol_node_key {

    /* Network address and mask */
    char *addr;
    size_t addr_sz;

    char *mask;
    size_t mask_sz;

    /* Protocol */
    int proto;
};

/* Converts a string represtation (addr_str)
 * to a numeric representation (addr_bytes) */

static int node_parse_addr(sepol_handle_t * handle,
               const char *addr_str, int proto, char *addr_bytes)
{

    switch (proto) {

    case SEPOL_PROTO_IP4:
        {
            struct in_addr in_addr;

            if (inet_pton(AF_INET, addr_str, &in_addr) <= 0) {
                LOGD( "could not parse IPv4 address "
                    "%s: %s", addr_str, strerror(errno));
                return STATUS_ERR;
            }

            memcpy(addr_bytes, &in_addr.s_addr, 4);
            break;
        }
    case SEPOL_PROTO_IP6:
        {
            struct in6_addr in_addr;

            if (inet_pton(AF_INET6, addr_str, &in_addr) <= 0) {
                LOGD( "could not parse IPv6 address "
                    "%s: %s", addr_str, strerror(errno));
                return STATUS_ERR;
            }

#ifdef DARWIN
            memcpy(addr_bytes, in_addr.s6_addr, 16);
#else
            memcpy(addr_bytes, in_addr.s6_addr32, 16);
#endif
            break;
        }
    default:
        LOGD( "unsupported protocol %u, could not "
            "parse address", proto);
        return STATUS_ERR;
    }

    return STATUS_SUCCESS;
}

/* Allocates a sufficiently large buffer (addr, addr_sz)
 * according the the protocol */

static int node_alloc_addr(sepol_handle_t * handle,
               int proto, char **addr, size_t * addr_sz)
{

    char *tmp_addr = NULL;
    size_t tmp_addr_sz;

    switch (proto) {

    case SEPOL_PROTO_IP4:
        tmp_addr_sz = 4;
        tmp_addr = malloc(4);
        if (!tmp_addr)
            goto omem;
        break;

    case SEPOL_PROTO_IP6:
        tmp_addr_sz = 16;
        tmp_addr = malloc(16);
        if (!tmp_addr)
            goto omem;
        break;

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

    *addr = tmp_addr;
    *addr_sz = tmp_addr_sz;
    return STATUS_SUCCESS;

      omem:
    LOGD( "out of memory");

      err:
    free(tmp_addr);
    LOGD( "could not allocate address of protocol %s",
        sepol_node_get_proto_str(proto));
    return STATUS_ERR;
}

/* Converts a numeric representation (addr_bytes)
 * to a string representation (addr_str), according to 
 * the protocol */

static int node_expand_addr(sepol_handle_t * handle,
                char *addr_bytes, int proto, char *addr_str)
{

    switch (proto) {

    case SEPOL_PROTO_IP4:
        {
            struct in_addr addr;
            memset(&addr, 0, sizeof(struct in_addr));
            memcpy(&addr.s_addr, addr_bytes, 4);

            if (inet_ntop(AF_INET, &addr, addr_str,
                      INET_ADDRSTRLEN) == NULL) {

                LOGD(
                    "could not expand IPv4 address to string: %s",
                    strerror(errno));
                return STATUS_ERR;
            }
            break;
        }

    case SEPOL_PROTO_IP6:
        {
            struct in6_addr addr;
            memset(&addr, 0, sizeof(struct in6_addr));
#ifdef DARWIN
            memcpy(&addr.s6_addr[0], addr_bytes, 16);
#else
            memcpy(&addr.s6_addr32[0], addr_bytes, 16);
#endif
            if (inet_ntop(AF_INET6, &addr, addr_str,
                      INET6_ADDRSTRLEN) == NULL) {

                LOGD(
                    "could not expand IPv6 address to string: %s",
                    strerror(errno));
                return STATUS_ERR;
            }
            break;
        }

    default:
        LOGD( "unsupported protocol %u, could not"
            " expand address to string", proto);
        return STATUS_ERR;
    }

    return STATUS_SUCCESS;
}

/* Allocates a sufficiently large address string (addr)
 * according to the protocol */

static int node_alloc_addr_string(sepol_handle_t * handle,
                  int proto, char **addr)
{

    char *tmp_addr = NULL;

    switch (proto) {

    case SEPOL_PROTO_IP4:
        tmp_addr = malloc(INET_ADDRSTRLEN);
        if (!tmp_addr)
            goto omem;
        break;

    case SEPOL_PROTO_IP6:
        tmp_addr = malloc(INET6_ADDRSTRLEN);
        if (!tmp_addr)
            goto omem;
        break;

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

    *addr = tmp_addr;
    return STATUS_SUCCESS;

      omem:
    LOGD( "out of memory");

      err:
    free(tmp_addr);
    LOGD( "could not allocate string buffer for "
        "address of protocol %s", sepol_node_get_proto_str(proto));
    return STATUS_ERR;
}

/* Key */
int sepol_node_key_create(sepol_handle_t * handle,
              const char *addr,
              const char *mask,
              int proto, sepol_node_key_t ** key_ptr)
{

    sepol_node_key_t *tmp_key =
        (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
    if (!tmp_key)
        goto omem;

    if (node_alloc_addr(handle, proto, &tmp_key->addr, &tmp_key->addr_sz) <
        0)
        goto err;
    if (node_parse_addr(handle, addr, proto, tmp_key->addr) < 0)
        goto err;

    if (node_alloc_addr(handle, proto, &tmp_key->mask, &tmp_key->mask_sz) <
        0)
        goto err;
    if (node_parse_addr(handle, mask, proto, tmp_key->mask) < 0)
        goto err;

    tmp_key->proto = proto;

    *key_ptr = tmp_key;
    return STATUS_SUCCESS;

      omem:
    LOGD( "out of memory");

      err:
    sepol_node_key_free(tmp_key);
    LOGD( "could not create node key for (%s, %s, %s)",
        addr, mask, sepol_node_get_proto_str(proto));
    return STATUS_ERR;
}

hidden_def(sepol_node_key_create)

void sepol_node_key_unpack(const sepol_node_key_t * key,
               const char **addr, const char **mask, int *proto)
{

    *addr = key->addr;
    *mask = key->mask;
    *proto = key->proto;
}

hidden_def(sepol_node_key_unpack)

int sepol_node_key_extract(sepol_handle_t * handle,
               const sepol_node_t * node,
               sepol_node_key_t ** key_ptr)
{

    sepol_node_key_t *tmp_key =
        (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
    if (!tmp_key)
        goto omem;

    tmp_key->addr = malloc(node->addr_sz);
    tmp_key->mask = malloc(node->mask_sz);

    if (!tmp_key->addr || !tmp_key->mask)
        goto omem;

    memcpy(tmp_key->addr, node->addr, node->addr_sz);
    memcpy(tmp_key->mask, node->mask, node->mask_sz);
    tmp_key->addr_sz = node->addr_sz;
    tmp_key->mask_sz = node->mask_sz;
    tmp_key->proto = node->proto;

    *key_ptr = tmp_key;
    return STATUS_SUCCESS;

      omem:
    sepol_node_key_free(tmp_key);
    LOGD( "out of memory, could not extract node key");
    return STATUS_ERR;
}

void sepol_node_key_free(sepol_node_key_t * key)
{

    if (!key)
        return;

    free(key->addr);
    free(key->mask);
    free(key);
}

hidden_def(sepol_node_key_free)

int sepol_node_compare(const sepol_node_t * node, const sepol_node_key_t * key)
{

    int rc1, rc2;

    if ((node->addr_sz < key->addr_sz) || (node->mask_sz < key->mask_sz))
        return -1;

    else if ((node->addr_sz > key->addr_sz) ||
         (node->mask_sz > key->mask_sz))
        return 1;

    rc1 = memcmp(node->addr, key->addr, node->addr_sz);
    rc2 = memcmp(node->mask, key->mask, node->mask_sz);

    return (rc2 != 0) ? rc2 : rc1;
}

int sepol_node_compare2(const sepol_node_t * node, const sepol_node_t * node2)
{

    int rc1, rc2;

    if ((node->addr_sz < node2->addr_sz) ||
        (node->mask_sz < node2->mask_sz))
        return -1;

    else if ((node->addr_sz > node2->addr_sz) ||
         (node->mask_sz > node2->mask_sz))
        return 1;

    rc1 = memcmp(node->addr, node2->addr, node->addr_sz);
    rc2 = memcmp(node->mask, node2->mask, node->mask_sz);

    return (rc2 != 0) ? rc2 : rc1;
}

/* Addr */
int sepol_node_get_addr(sepol_handle_t * handle,
            const sepol_node_t * node, char **addr)
{

    char *tmp_addr = NULL;

    if (node_alloc_addr_string(handle, node->proto, &tmp_addr) < 0)
        goto err;

    if (node_expand_addr(handle, node->addr, node->proto, tmp_addr) < 0)
        goto err;

    *addr = tmp_addr;
    return STATUS_SUCCESS;

      err:
    free(tmp_addr);
    LOGD( "could not get node address");
    return STATUS_ERR;
}

hidden_def(sepol_node_get_addr)

int sepol_node_get_addr_bytes(sepol_handle_t * handle,
                  const sepol_node_t * node,
                  char **buffer, size_t * bsize)
{

    char *tmp_buf = malloc(node->addr_sz);
    if (!tmp_buf) {
        LOGD( "out of memory, could not get address bytes");
        return STATUS_ERR;
    }

    memcpy(tmp_buf, node->addr, node->addr_sz);
    *buffer = tmp_buf;
    *bsize = node->addr_sz;
    return STATUS_SUCCESS;
}

hidden_def(sepol_node_get_addr_bytes)

int sepol_node_set_addr(sepol_handle_t * handle,
            sepol_node_t * node, int proto, const char *addr)
{

    char *tmp_addr = NULL;
    size_t tmp_addr_sz;

    if (node_alloc_addr(handle, proto, &tmp_addr, &tmp_addr_sz) < 0)
        goto err;

    if (node_parse_addr(handle, addr, proto, tmp_addr) < 0)
        goto err;

    free(node->addr);
    node->addr = tmp_addr;
    node->addr_sz = tmp_addr_sz;
    return STATUS_SUCCESS;

      err:
    free(tmp_addr);
    LOGD( "could not set node address to %s", addr);
    return STATUS_ERR;
}

hidden_def(sepol_node_set_addr)

int sepol_node_set_addr_bytes(sepol_handle_t * handle,
                  sepol_node_t * node,
                  const char *addr, size_t addr_sz)
{

    char *tmp_addr = malloc(addr_sz);
    if (!tmp_addr) {
        LOGD( "out of memory, could not " "set node address");
        return STATUS_ERR;
    }

    memcpy(tmp_addr, addr, addr_sz);
    free(node->addr);
    node->addr = tmp_addr;
    node->addr_sz = addr_sz;
    return STATUS_SUCCESS;
}

hidden_def(sepol_node_set_addr_bytes)

/* Mask */
int sepol_node_get_mask(sepol_handle_t * handle,
            const sepol_node_t * node, char **mask)
{

    char *tmp_mask = NULL;

    if (node_alloc_addr_string(handle, node->proto, &tmp_mask) < 0)
        goto err;

    if (node_expand_addr(handle, node->mask, node->proto, tmp_mask) < 0)
        goto err;

    *mask = tmp_mask;
    return STATUS_SUCCESS;

      err:
    free(tmp_mask);
    LOGD( "could not get node netmask");
    return STATUS_ERR;
}

hidden_def(sepol_node_get_mask)

int sepol_node_get_mask_bytes(sepol_handle_t * handle,
                  const sepol_node_t * node,
                  char **buffer, size_t * bsize)
{

    char *tmp_buf = malloc(node->mask_sz);
    if (!tmp_buf) {
        LOGD( "out of memory, could not get netmask bytes");
        return STATUS_ERR;
    }

    memcpy(tmp_buf, node->mask, node->mask_sz);
    *buffer = tmp_buf;
    *bsize = node->mask_sz;
    return STATUS_SUCCESS;
}

hidden_def(sepol_node_get_mask_bytes)

int sepol_node_set_mask(sepol_handle_t * handle,
            sepol_node_t * node, int proto, const char *mask)
{

    char *tmp_mask = NULL;
    size_t tmp_mask_sz;

    if (node_alloc_addr(handle, proto, &tmp_mask, &tmp_mask_sz) < 0)
        goto err;

    if (node_parse_addr(handle, mask, proto, tmp_mask) < 0)
        goto err;

    free(node->mask);
    node->mask = tmp_mask;
    node->mask_sz = tmp_mask_sz;
    return STATUS_SUCCESS;

      err:
    free(tmp_mask);
    LOGD( "could not set node netmask to %s", mask);
    return STATUS_ERR;
}

hidden_def(sepol_node_set_mask)

int sepol_node_set_mask_bytes(sepol_handle_t * handle,
                  sepol_node_t * node,
                  const char *mask, size_t mask_sz)
{

    char *tmp_mask = malloc(mask_sz);
    if (!tmp_mask) {
        LOGD( "out of memory, could not " "set node netmask");
        return STATUS_ERR;
    }
    memcpy(tmp_mask, mask, mask_sz);
    free(node->mask);
    node->mask = tmp_mask;
    node->mask_sz = mask_sz;
    return STATUS_SUCCESS;
}

hidden_def(sepol_node_set_mask_bytes)

/* Protocol */
int sepol_node_get_proto(const sepol_node_t * node)
{

    return node->proto;
}

hidden_def(sepol_node_get_proto)

void sepol_node_set_proto(sepol_node_t * node, int proto)
{

    node->proto = proto;
}

hidden_def(sepol_node_set_proto)

const char *sepol_node_get_proto_str(int proto)
{

    switch (proto) {
    case SEPOL_PROTO_IP4:
        return "ipv4";
    case SEPOL_PROTO_IP6:
        return "ipv6";
    default:
        return "???";
    }
}

hidden_def(sepol_node_get_proto_str)

/* Create */
int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node)
{

    sepol_node_t *tmp_node = (sepol_node_t *) malloc(sizeof(sepol_node_t));

    if (!tmp_node) {
        LOGD( "out of memory, could not create " "node record");
        return STATUS_ERR;
    }

    tmp_node->addr = NULL;
    tmp_node->addr_sz = 0;
    tmp_node->mask = NULL;
    tmp_node->mask_sz = 0;
    tmp_node->proto = SEPOL_PROTO_IP4;
    tmp_node->con = NULL;
    *node = tmp_node;

    return STATUS_SUCCESS;
}

hidden_def(sepol_node_create)

/* Deep copy clone */
int sepol_node_clone(sepol_handle_t * handle,
             const sepol_node_t * node, sepol_node_t ** node_ptr)
{

    sepol_node_t *new_node = NULL;
    if (sepol_node_create(handle, &new_node) < 0)
        goto err;

    /* Copy address, mask, protocol */
    new_node->addr = malloc(node->addr_sz);
    new_node->mask = malloc(node->mask_sz);
    if (!new_node->addr || !new_node->mask)
        goto omem;

    memcpy(new_node->addr, node->addr, node->addr_sz);
    memcpy(new_node->mask, node->mask, node->mask_sz);
    new_node->addr_sz = node->addr_sz;
    new_node->mask_sz = node->mask_sz;
    new_node->proto = node->proto;

    /* Copy context */
    if (node->con &&
        (sepol_context_clone(handle, node->con, &new_node->con) < 0))
        goto err;

    *node_ptr = new_node;
    return STATUS_SUCCESS;

      omem:
    LOGD( "out of memory");

      err:
    LOGD( "could not clone node record");
    sepol_node_free(new_node);
    return STATUS_ERR;
}

/* Destroy */
void sepol_node_free(sepol_node_t * node)
{

    if (!node)
        return;

    sepol_context_free(node->con);
    free(node->addr);
    free(node->mask);
    free(node);
}

hidden_def(sepol_node_free)

/* Context */
sepol_context_t *sepol_node_get_con(const sepol_node_t * node)
{

    return node->con;
}

hidden_def(sepol_node_get_con)

int sepol_node_set_con(sepol_handle_t * handle,
               sepol_node_t * node, sepol_context_t * con)
{

    sepol_context_t *newcon;

    if (sepol_context_clone(handle, con, &newcon) < 0) {
        LOGD( "out of memory, could not set node context");
        return STATUS_ERR;
    }

    sepol_context_free(node->con);
    node->con = newcon;
    return STATUS_SUCCESS;
}

hidden_def(sepol_node_set_con)