#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>

#define EXEC_SIZE 64
#define CODE_WRITE 1
#define CODE_AS_IS 0

typedef unsigned char u8;
typedef unsigned int u32;

static u8 data_area[EXEC_SIZE];

#define REC_STACK_SIZE (0x1000 / 8)
#define REC_NUM_DEFAULT ((0x1000 / REC_STACK_SIZE) * 2)

static int recur_count = REC_NUM_DEFAULT;

static void do_nothing(void)
{
return;
}

void lkdtm_rodata_do_nothing(void)
{
/* Does nothing. We just want an architecture agnostic "return". */
}

void execute_location(void *dst, int write)
{
void (*func)(void) = dst;

printf("attempting ok execution at do_nothing \n");
do_nothing();

if (write == CODE_WRITE) {
memcpy(dst, (const void*)do_nothing, EXEC_SIZE);
}
printf("attempting bad execution at func\n");
func();
}

void lkdtm_EXEC_NULL(void)
{
execute_location(NULL, CODE_AS_IS);
}

void trace_exec_null(void)
{
printf("trace exec null \n");
lkdtm_EXEC_NULL();
}

void lkdtm_EXEC_DATA(void)
{
execute_location(data_area, CODE_WRITE);
}

void trace_exec_data(void)
{
printf("trace exec data \n");
lkdtm_EXEC_DATA();
}

void lkdtm_EXEC_STACK(void)
{
u8 stack_area[EXEC_SIZE];
execute_location(stack_area, CODE_WRITE);
}

void trace_exec_stack(void)
{
printf("trace exec stack \n");
lkdtm_EXEC_STACK();
}

void lkdtm_EXEC_MALLOC(void)
{
u32 *malloc_area = malloc(EXEC_SIZE);
execute_location(malloc_area, CODE_WRITE);
free(malloc_area);
}

void trace_exec_malloc(void)
{
printf("trace exec malloc \n");
lkdtm_EXEC_MALLOC();
}

void lkdtm_EXEC_RODATA(void)
{
execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS);
}

void trace_exec_rodata(void)
{
printf("trace exec rodata \n");
lkdtm_EXEC_RODATA();
}

void lkdtm_ACCESS_NULL(void)
{
unsigned long tmp;
unsigned long *ptr = (unsigned long *)NULL;

printf("attempting bad read at \n");
tmp = *ptr;
tmp += 0xc0dec0de;

printf("attempting bad write at \n");
*ptr = tmp;

printf("finishing bad write at \n");
}

void trace_access_null(void)
{
        printf("trace accesss null \n");
lkdtm_ACCESS_NULL();
}

void lkdtm_EXEC_ASSERT(void)
{
assert(1);
printf("finishing assert \n");
}

void trace_exec_assert(void)
{
        printf("trace exec assert \n");
lkdtm_EXEC_ASSERT();
}

void lkdtm_CORRUPT_STACK(int remaining)
{
/* Use default char array length that triggers stack protection. */
char data[8];

// memset((void *)data, 0, 64);
memset((void *)data, (remaining & 0xff) | 0x1, (remaining & 0xff) | 0xff);
}

void trace_corrupt_stack(void)
{
        printf("trace corrupt stack \n");
lkdtm_CORRUPT_STACK(recur_count);
}

static int recursive_loop(int remaining)
{
char buf[REC_STACK_SIZE];

/* Make sure compiler does not optimize this away. */
memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE);
if (!remaining)
return 0;
else
return recursive_loop(remaining - 1);
}

void lkdtm_OVERFLOW(void)
{
(void) recursive_loop(recur_count);
}

void trace_stack_overflow(void)
{
        printf("trace stack overflow \n");
lkdtm_OVERFLOW();
}

int main(int argc, char *argv[])
{
        char *param = argv[1];

if(argc == 0) {
printf("check argument \n");

return 0;
}

        if (!strcmp("exec_null", param)) {
         trace_exec_null();
        }

        else if (!strcmp("exec_assert", param)) {
         trace_exec_assert();
        }
else if(!strcmp("access_null", param)) {
trace_access_null();
}

else if(!strcmp("exec_data", param)) {
trace_exec_data();
}

else if(!strcmp("exec_stack", param)) {
trace_exec_stack();
}

else if(!strcmp("exec_malloc", param)) {
trace_exec_malloc();
}

else if(!strcmp("exec_rodata", param)) {
trace_exec_rodata();
}

else if(!strcmp("corrupt_stack", param)) {
trace_corrupt_stack();
}

else if(!strcmp("stack_overflow", param)) {
trace_stack_overflow();
}

        return 0;
}

+ Recent posts