mov eax , cr0
or eax , 0x01
mov cr0 , eax



back to months list

Project : Research on Multi-platform System Call Table

Journal Entry Date : 2024.03.27

Turns out the "real" sys_call_table existed in the file "arch/x86/entry/syscall_64.c" At least now I know.

I changed the system call table from array to pointer to make it switchable. When I tried to actually register the system call tables, I realized some problems in this system.

  1. Wiring the table with binary handler
    How am I suppose to get the binary handler that I want? How do I know what binary handler is what? Or should we even use the binary handler as recognizer...?
  2. Different methods of calling the systemcall for different tables
    The method of calling the system call might be different. (For example, Linux uses the interrupt number 0x80, but windows uses 0x2E. )

First problem is my concern. Second problem can be easily fixed by just making that interrupt line to also handle system call, but first problem is a bit complicated problem.

I am thinking of reversing the process of registering. Instead of one function searching for matching binary handlers and registering all the table, making binary handler choose the system call table makes system quite simple. I'm thinking of system that can just add the binary handler to already-registered system call tables by binary handler module.

So I modified some interface functions :

struct sys_call_array_container { 
    char platform[30];
    // binary handler
    struct linux_binfmt *bin_handler;
    // system call table
    sys_call_ptr_t *tbl_ptr;

    struct list_head lst;
};

// Add system call table to list
void sys_tbl_init_list(void);
void sys_tbl_add(sys_call_ptr_t *tbl_ptr , const char *platform);
void sys_tbl_set_binary_handler(struct linux_binfmt *bin_handler , const char *platform);
sys_call_ptr_t *sys_tbl_search_by_bin_handler(struct linux_binfmt *bin_handler);

// architecture-dependent
void sys_tbl_register_systbls(void);

"platform" field is added to the list to find the system call table easily, because you can just search for platform to register the binary handler, instead of searching for pointer of system call table.

The system call tables are first added to system(by calling system_tbl_register_systbls() function), and then the binary handlers are linked using the sys_tbl_set_binary_handler() function. Registering all the system call handlers are done in sys_tbl_register_sytbls() function.

sys_call_ptr_t sys_call_table_linux[] = {
#include <asm/syscalls_64.h> // ../include/generated/asm/syscalls_64.h
};

sys_call_ptr_t sys_call_table_other[] = {
__SYSCALL(69, sys_write)
};

asmlinkage sys_call_ptr_t *sys_call_table = sys_call_table_linux;

#include 

void sys_tbl_register_systbls(void) {
    sys_tbl_add(sys_call_table_linux , "linux");
    sys_tbl_add(sys_call_table_other , "mysyscalltable");
}

This function is called in the initialization sequence, at the end of kernel_init_freeable() function in "main.c"

...

	integrity_load_keys();

	// initialize the list and register all the system calls to the list
	sys_tbl_init_list();
}

...And now what I have to do is just link the system call table to the binary loader.

static int __init init_elf_binfmt(void)
{
	register_binfmt(&elf_format);
	sys_tbl_set_binary_handler(&elf_format , "linux");
	return 0;
}

Now what we have to do is simple. First, modify context switching code so that system call table is also exchanged when switching the context. Second, create some loader to test whether the system call translation works.

I tried making a pseudo binary loader for testing, and I found that binary handler is a module, not integrated to kernel. I'm thinking of making a exe file loader module... which is going to be very hard.

To make this possible, we need a field in PCB(Process Control Block) that stores its system call table. I added this field to "linux_binprm" structure to temporarily store and finally send the table pointer to PCB..

struct linux_binprm {
        ...
	char buf[BINPRM_BUF_SIZE];

	// added new system call table pointer
	sys_call_ptr_t *sys_call_tbl_ptr;
} __randomize_layout;

...And we need to get the right system call table by detected binary handler. We just need to get what table is linked to the loader that we got from search_binary_handler() function.

static int search_binary_handler(struct linux_binprm *bprm)
{
	bool need_retry = IS_ENABLED(CONFIG_MODULES);
	struct linux_binfmt *fmt;
	int retval;

...
	
	bprm->sys_call_tbl_ptr = sys_tbl_search_by_bin_handler(fmt);

	return retval;
}

Now we somehow need to save this table information to PCB and add new binary handler. I need to understand the process of making the module for kernel, because I need to make a module of a binary handler. I also need to understand how to make binary handler and exe file format.. ugh.