rapid7/metasploit-framework

View on GitHub
external/source/exploits/CVE-2018-4237/libspc/dictionary.c

Summary

Maintainability
Test Coverage
#include "datatypes.h"
#include "utils.h"

#include <stdlib.h>
#include <stdio.h>

extern int fileport_makeport(int fd, mach_port_t* port);

spc_dictionary_t* spc_dictionary_create()
{
    return calloc(sizeof(spc_dictionary_t), 1);
}

void spc_dictionary_destroy(spc_dictionary_t* dict)
{
    spc_dictionary_item_t* current, *last;
    current = dict->items;
    while (current) {
        free(current->key);

        spc_value_destroy(current->value);

        last = current;
        current = current->next;
        free(last);
    }

    free(dict);
}

spc_dictionary_item_t* spc_dictionary_lookup(spc_dictionary_t* dict, const char* key)
{
    spc_dictionary_item_t* current = dict->items;
    while (current) {
        if (strcmp(current->key, key) == 0)
            return current;

        current = current->next;
    }

    return NULL;
}

spc_dictionary_item_t* spc_dictionary_add_item(spc_dictionary_t* dict, const char* key, uint32_t type)
{
    spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
    if (item) {
        spc_value_destroy(item->value);
    } else {
        item = malloc(sizeof(spc_dictionary_item_t));
        item->next = dict->items;
        dict->items = item;
        dict->num_items++;
        item->key = strdup(key);
    }
    item->value.type = type;
    return item;
}

void spc_dictionary_set_value(spc_dictionary_t* dict, const char* key, spc_value_t value)
{
    spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_STRING);
    item->value = value;
}

void spc_dictionary_set_string(spc_dictionary_t* dict, const char* key, const char* value)
{
    spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_STRING);
    item->value.value.str = strdup(value);
}

void spc_dictionary_set_uint64(spc_dictionary_t* dict, const char* key, uint64_t value)
{
    spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_UINT64);
    item->value.value.u64 = value;
}

void spc_dictionary_set_int64(spc_dictionary_t* dict, const char* key, int64_t value)
{
    spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_INT64);
    item->value.value.i64 = value;
}

void spc_dictionary_set_data(spc_dictionary_t* dict, const char* key, const void* bytes, size_t len)
{
    spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_DATA);
    void* buf = malloc(len);
    memcpy(buf, bytes, len);
    item->value.value.data.ptr = buf;
    item->value.value.data.size = len;
}

void spc_dictionary_set_fd(spc_dictionary_t* dict, const char* key, int fd)
{
    mach_port_t fileport;
    fileport_makeport(fd, &fileport);

    spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_FD);
    item->value.value.port.name = fileport;
    item->value.value.port.type = MACH_MSG_TYPE_COPY_SEND;
}

// TODO make port type a parameter
void spc_dictionary_set_send_port(spc_dictionary_t* dict, const char* key, mach_port_t port)
{
    mach_port_addref(port, MACH_PORT_RIGHT_SEND);

    spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_SEND_PORT);
    item->value.value.port.name = port;
    item->value.value.port.type = MACH_MSG_TYPE_COPY_SEND;
}

void spc_dictionary_set_receive_port(spc_dictionary_t* dict, const char* key, mach_port_t port)
{
    mach_port_addref(port, MACH_PORT_RIGHT_RECEIVE);

    spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_RECV_PORT);
    item->value.value.port.name = port;
    item->value.value.port.type = MACH_MSG_TYPE_MOVE_RECEIVE;
}

void spc_dictionary_set_bool(spc_dictionary_t* dict, const char* key, int value)
{
    spc_dictionary_item_t* item = spc_dictionary_add_item(dict, key, SPC_TYPE_BOOL);
    item->value.value.u64 = value;
}

uint64_t spc_dictionary_get_uint64(spc_dictionary_t* dict, const char* key)
{
    spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
    if (!item || item->value.type != SPC_TYPE_UINT64)
        return 0;

    return item->value.value.u64;
}

int64_t spc_dictionary_get_int64(spc_dictionary_t* dict, const char* key)
{
    spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
    if (!item || item->value.type != SPC_TYPE_INT64)
        return 0;

    return item->value.value.i64;
}

const char* spc_dictionary_get_string(spc_dictionary_t* dict, const char* key)
{
    spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
    if (!item || item->value.type != SPC_TYPE_STRING)
        return NULL;

    return item->value.value.str;
}

int spc_dictionary_get_bool(spc_dictionary_t* dict, const char* key)
{
    spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
    if (!item || item->value.type != SPC_TYPE_BOOL)
        return 0;

    return item->value.value.u64;
}

mach_port_t spc_dictionary_get_send_port(spc_dictionary_t* dict, const char* key)
{
    spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
    if (!item || item->value.type != SPC_TYPE_SEND_PORT)
        return MACH_PORT_NULL;

    mach_port_addref(item->value.value.port.name, MACH_PORT_RIGHT_SEND);
    return item->value.value.port.name;
}

mach_port_t spc_dictionary_get_receive_port(spc_dictionary_t* dict, const char* key)
{
    spc_dictionary_item_t* item = spc_dictionary_lookup(dict, key);
    if (!item || item->value.type != SPC_TYPE_RECV_PORT)
        return MACH_PORT_NULL;

    mach_port_addref(item->value.value.port.name, MACH_PORT_RIGHT_RECEIVE);
    return item->value.value.port.name;
}


void spc_dump_value(spc_value_t value, int indent)
{
    char* indent_str = malloc(indent + 1);
    memset(indent_str, ' ', indent);
    indent_str[indent] = 0;

    switch (value.type) {
        case SPC_TYPE_NULL:
            printf("%*cnull\n", indent, ' ');
            break;
        case SPC_TYPE_BOOL:
            printf("%*c%s\n", indent, ' ', value.value.u64 ? "true" : "false");
            break;
        case SPC_TYPE_UINT64:
            printf("%*c%llu\n", indent, ' ', value.value.u64);
            break;
        case SPC_TYPE_INT64:
            printf("%*c%lli\n", indent, ' ', value.value.i64);
            break;
        case SPC_TYPE_DOUBLE:
            printf("%*c%f\n", indent, ' ', value.value.dbl);
            break;
        case SPC_TYPE_STRING:
            printf("%*c%s\n", indent, ' ', value.value.str);
            break;
        case SPC_TYPE_UUID: {
            char buf[0x21];
            for (int i = 0; i < 0x10; i++) {
                sprintf(&buf[2*i], "%02x", ((unsigned char*)value.value.str)[i]);
            }
            buf[0x20] = 0;
            printf("%*cuuid: %s\n", indent, ' ', buf);
            break;
        }
        case SPC_TYPE_ARRAY: {
            spc_array_t* array = value.value.array;
            printf("%*c[\n", indent, ' ');
            for (size_t i = 0; i < array->length; i++) {
                spc_dump_value(array->values[i], indent + 2);
            }
            printf("%*c]\n", indent, ' ');
            break;
        }
        case SPC_TYPE_DICT: {
            spc_dictionary_item_t* current = value.value.dict->items;
            while (current) {
                printf("%*c%s:\n", indent, ' ', current->key);
                spc_dump_value(current->value, indent + 2);
                current = current->next;
            }
            break;
        }
        case SPC_TYPE_SEND_PORT:
            printf("%*cport send right: %d\n", indent, ' ', value.value.port.name);
            break;
        case SPC_TYPE_RECV_PORT:
            printf("%*cport receive right: %d\n", indent, ' ', value.value.port.name);
            break;
        case SPC_TYPE_DATA:
            printf("%*cdata: 0x", indent, ' ');
            for (size_t i = 0; i < value.value.data.size; i++)
                printf("%02x", value.value.data.ptr[i]);
            printf("\n");
            break;
        default:
            printf("%*cUnknown item of type %d\n", indent, ' ', value.type);
    }

    free(indent_str);
}

void spc_dump(spc_dictionary_t* dict)
{
    spc_value_t value;
    value.type = SPC_TYPE_DICT;
    value.value.dict = dict;
    spc_dump_value(value, 0);
}