Skip to content

Commit

Permalink
对syscall进行内存安全检查
Browse files Browse the repository at this point in the history
  • Loading branch information
copi143 committed Dec 19, 2024
1 parent dd468a7 commit 233f206
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 38 deletions.
2 changes: 2 additions & 0 deletions include/kernel/mtask.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ task_t task_run(task_t task);
void task_exit(i32 status) __attr(noreturn);
// 杀死任务
void task_kill(task_t task);
// 异常退出
void task_abort() __attr(noreturn);

/**
*\brief 通过任务 ID 获取任务
Expand Down
27 changes: 27 additions & 0 deletions include/kernel/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,30 @@ enum {
PAGE_TYPE_HEAP, // 堆页
PAGE_TYPE_ALLOC, // 分配页
};

/**
*\brief 检查用户是否有对指定内存地址的访问权限
*
*\param addr 内存地址
*\param wr 是否写权限
*\return 是否有权限
*/
bool check_address_permission(const void *addr, bool wr);

/**
*\brief 检查用户是否有对指定内存区域的访问权限
*
*\param addr 内存地址
*\param size 内存大小
*\param wr 是否写权限
*\return 是否有权限
*/
bool check_memory_permission(const void *addr, size_t size, bool wr);

/**
*\brief 检查用户是否有对指定字符串的读取权限
*
*\param addr 内存地址
*\return 是否有权限
*/
bool check_string_permission(cstr addr);
9 changes: 7 additions & 2 deletions src/kernel/cpu/cpu_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,13 @@ __attr(fastcall) void error_inthandler(i32 id, regs32 *regs) {
kassert(id >= 0);
kassert(id < 32);
kassert(regs != null);
if (regs->fs != RING0_DS) task_kill(current_task);
klogf("%02x: %s (#%s)", id, error_names[id].fullname, error_names[id].shortname);
if (regs->fs != RING0_DS) {
klogw("task %d error %02x: %s (#%s)", current_task->tid, id, error_names[id].fullname,
error_names[id].shortname);
task_abort();
__builtin_unreachable();
}
klogf("error %02x: %s (#%s)", id, error_names[id].fullname, error_names[id].shortname);
abort();
}

Expand Down
10 changes: 5 additions & 5 deletions src/kernel/exec/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ void task_to_user_mode_elf();
extern TSS32 tss;
extern PageInfo *pages;

#define IDX(addr) ((u32)(addr) >> 12) // 获取 addr 的页索引
#define DIDX(addr) (((u32)(addr) >> 22) & 0x3ff) // 获取 addr 的页目录索引
#define TIDX(addr) (((u32)(addr) >> 12) & 0x3ff) // 获取 addr 的页表索引
#define PAGE(idx) ((u32)(idx) << 12) // 获取页索引 idx 对应的页开始的位置
#define IDX(addr) ((u32)(addr) >> 12) // 获取 addr 的页索引
#define PDI(addr) (((u32)(addr) >> 22) & 0x3ff) // 获取 addr 的页目录索引
#define PTI(addr) (((u32)(addr) >> 12) & 0x3ff) // 获取 addr 的页表索引
#define PAGE(idx) ((u32)(idx) << 12) // 获取页索引 idx 对应的页开始的位置

void task_app() {
klogd("%s", current_task->command_line);
Expand All @@ -31,7 +31,7 @@ void task_app() {
asm_set_cr3(PD_ADDRESS);
current_task->cr3 = PD_ADDRESS;
klogd("P1 %08x", current_task->cr3);
for (int i = DIDX(0x70000000) * 4; i < PAGE_SIZE; i += 4) {
for (int i = PDI(0x70000000) * 4; i < PAGE_SIZE; i += 4) {
u32 *pde_entry = (u32 *)(pde + i);

if ((*pde_entry & PAGE_SHARED) || pages[IDX(*pde_entry)].count > 1) {
Expand Down
81 changes: 56 additions & 25 deletions src/kernel/mm/vpage.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include <kernel.h>

#define IDX(addr) ((u32)(addr) >> 12) // 获取 addr 的页索引
#define DIDX(addr) (((u32)(addr) >> 22) & 0x3ff) // 获取 addr 的页目录索引
#define TIDX(addr) (((u32)(addr) >> 12) & 0x3ff) // 获取 addr 的页表索引
#define PAGE(idx) ((u32)(idx) << 12) // 获取页索引 idx 对应的页开始的位置
#define IDX(addr) ((u32)(addr) >> 12) // 获取 addr 的页索引
#define PDI(addr) (((u32)(addr) >> 22) & 0x3ff) // 获取 addr 的页目录索引
#define PTI(addr) (((u32)(addr) >> 12) & 0x3ff) // 获取 addr 的页表索引
#define PAGE(idx) ((u32)(idx) << 12) // 获取页索引 idx 对应的页开始的位置

static inthandler_f page_fault;

Expand Down Expand Up @@ -47,7 +47,7 @@ void page_set_alloced(PageInfo *pg, u32 start, u32 end) {
// OS应该是用不完0x70000000的,所以应用程序大概是可以用满2GB

u32 pd_clone(u32 addr) {
for (int i = DIDX(0x70000000) * 4; i < PAGE_SIZE; i += 4) {
for (int i = PDI(0x70000000) * 4; i < PAGE_SIZE; i += 4) {
u32 *pde_entry = (u32 *)(addr + i);
u32 p = *pde_entry & (0xfffff000);
pages[IDX(*pde_entry)].count++;
Expand All @@ -74,15 +74,15 @@ u32 pd_clone(u32 addr) {
}

static void pde_reset(u32 addr) {
for (int i = DIDX(0x70000000) * 4; i < PAGE_SIZE; i += 4) {
for (int i = PDI(0x70000000) * 4; i < PAGE_SIZE; i += 4) {
u32 *pde_entry = (u32 *)(addr + i);
*pde_entry |= PAGE_WRABLE;
}
}

void free_pde(u32 addr) {
if (addr == PD_ADDRESS) return;
for (int i = DIDX(0x70000000) * 4; i < DIDX(0xf1000000) * 4; i += 4) {
for (int i = PDI(0x70000000) * 4; i < PDI(0xf1000000) * 4; i += 4) {
u32 *pde_entry = (u32 *)(addr + i);
u32 p = *pde_entry & (0xfffff000);
if (!(*pde_entry & PAGE_USER) && !(*pde_entry & PAGE_PRESENT)) { continue; }
Expand All @@ -102,7 +102,7 @@ static void page_link_pde(u32 addr, u32 pde) {
current_task->cr3 = PD_ADDRESS;
asm_set_cr3(PD_ADDRESS);
u32 t, p;
t = DIDX(addr);
t = PDI(addr);
p = (addr >> 12) & 0x3ff;
u32 *pte = (u32 *)((pde + t * 4));

Expand Down Expand Up @@ -133,7 +133,7 @@ void page_link_addr_pde(u32 addr, u32 pde, u32 map_addr) {
current_task->cr3 = PD_ADDRESS;
asm_set_cr3(PD_ADDRESS);
u32 t, p;
t = DIDX(addr);
t = PDI(addr);
p = (addr >> 12) & 0x3ff;
u32 *pte = (u32 *)((pde + t * 4));

Expand Down Expand Up @@ -164,7 +164,7 @@ static void page_link_pde_share(u32 addr, u32 pde) {
current_task->cr3 = PD_ADDRESS;
asm_set_cr3(PD_ADDRESS);
u32 t, p;
t = DIDX(addr);
t = PDI(addr);
p = (addr >> 12) & 0x3ff;
u32 *pte = (u32 *)((pde + t * 4));

Expand Down Expand Up @@ -201,7 +201,7 @@ static void page_link_pde_paddr(u32 addr, u32 pde, u32 *paddr1, u32 paddr2) {
current_task->cr3 = PD_ADDRESS;
asm_set_cr3(PD_ADDRESS);
u32 t, p;
t = DIDX(addr);
t = PDI(addr);
p = (addr >> 12) & 0x3ff;
u32 *pte = (u32 *)((pde + t * 4));
// klogd("*pte = %08x\n",*pte);
Expand Down Expand Up @@ -299,7 +299,7 @@ void page_unlink_pde(u32 addr, u32 pde) {
current_task->cr3 = PD_ADDRESS;
asm_set_cr3(PD_ADDRESS);
u32 t, p;
t = DIDX(addr);
t = PDI(addr);
p = (addr >> 12) & 0x3ff;
u32 *pte = (u32 *)((pde + t * 4));

Expand Down Expand Up @@ -514,23 +514,23 @@ void change_page_task_id(int task_id, void *p, u32 size) {
}

u32 page_get_attr(u32 pde, u32 vaddr) {
pde += (u32)(DIDX(vaddr) * 4);
pde += (u32)(PDI(vaddr) * 4);
void *pte = (void *)(*(u32 *)pde & 0xfffff000);
pte += (u32)(TIDX(vaddr) * 4);
pte += (u32)(PTI(vaddr) * 4);
return (*(u32 *)pte) & 0x00000fff;
}

u32 page_get_phy(u32 pde, u32 vaddr) {
pde += (u32)(DIDX(vaddr) * 4);
pde += (u32)(PDI(vaddr) * 4);
void *pte = (void *)(*(u32 *)pde & 0xfffff000);
pte += (u32)(TIDX(vaddr) * 4);
pte += (u32)(PTI(vaddr) * 4);
return (*(u32 *)pte) & 0xfffff000;
}

void copy_on_write(u32 vaddr) {
void *pd = (void *)current_task->cr3; // PDE页目录地址
void *pde = (void *)((u32)pd + (u32)(DIDX(vaddr) * 4)); // PTE地址
void *pde_phy = (void *)(*(u32 *)(pde) & 0xfffff000); // 页
void *pd = (void *)current_task->cr3; // PDE页目录地址
void *pde = (void *)((u32)pd + (u32)(PDI(vaddr) * 4)); // PTE地址
void *pde_phy = (void *)(*(u32 *)(pde) & 0xfffff000); // 页

if (!(*(u32 *)pde & PAGE_WRABLE) || !(*(u32 *)pde & PAGE_USER)) { // PDE如果不可写
// 不可写的话,就需要对PDE做COW操作
Expand All @@ -554,7 +554,7 @@ void copy_on_write(u32 vaddr) {
flush_tlb(*(u32 *)(pde));
}
void *pt = (void *)(*(u32 *)pde & 0xfffff000);
void *pte = pt + (u32)(TIDX(vaddr) * 4);
void *pte = pt + (u32)(PTI(vaddr) * 4);
if (!(*(u32 *)pte & PAGE_WRABLE)) {
if (pages[IDX(*(u32 *)pte)].count < 2 || // 只有一个人引用
*(u32 *)pte & PAGE_SHARED /*或 这是一个SHARED页*/) {
Expand Down Expand Up @@ -597,7 +597,7 @@ void page_set_physics_attr(u32 vaddr, void *paddr, u32 attr) {
current_task->cr3 = PD_ADDRESS;
asm_set_cr3(PD_ADDRESS);
u32 t, p;
t = DIDX(vaddr);
t = PDI(vaddr);
p = (vaddr >> 12) & 0x3ff;
u32 *pte = (u32 *)((cr3_backup + t * 4));
if (pages[IDX(*pte)].count > 1 && !(*pte & PAGE_SHARED)) { // 这里SHARED页就不进行COW操作
Expand All @@ -623,7 +623,7 @@ void page_set_physics_attr(u32 vaddr, void *paddr, u32 attr) {

void page_set_physics_attr_pde(u32 vaddr, void *paddr, u32 attr, u32 cr3_backup) {
u32 t, p;
t = DIDX(vaddr);
t = PDI(vaddr);
p = (vaddr >> 12) & 0x3ff;
u32 *pte = (u32 *)((cr3_backup + t * 4));
if (pages[IDX(*pte)].count > 1) { // 这里SHARED页就不进行COW操作
Expand Down Expand Up @@ -657,7 +657,7 @@ __attr(fastcall) void page_fault(i32 id, regs32 *regs) {
(!(page_get_attr(pde, (u32)line_address) & PAGE_USER))) { // 用户不可写
error("Attempt to read/write a non-existent/kernel memory %p at %p.", line_address, regs->eip);
if (current_task->user_mode) {
task_kill(current_task);
task_abort();
} else {
abort(); // 系统级FAULT
}
Expand All @@ -671,10 +671,41 @@ __attr(fastcall) void page_fault(i32 id, regs32 *regs) {
void page_set_attr(u32 start, u32 end, u32 attr, u32 pde) {
int count = PADDING_UP(end - start, PAGE_SIZE) / PAGE_SIZE;
for (int i = 0; i < count; i++) {
u32 *pde_entry = (u32 *)(pde + DIDX(start + i * PAGE_SIZE) * 4);
u32 *pde_entry = (u32 *)(pde + PDI(start + i * PAGE_SIZE) * 4);
u32 p = *pde_entry & (0xfffff000);
u32 *pte_entry = (u32 *)(p + TIDX(start + i * PAGE_SIZE) * 4);
u32 *pte_entry = (u32 *)(p + PTI(start + i * PAGE_SIZE) * 4);
*pte_entry |= attr;
}
asm_set_cr3(pde);
}

bool check_address_permission(const void *addr, bool wr) {
size_t cr3 = asm_get_cr3();
size_t pde = mem_get(cr3 + PDI(addr) * 4);
if (!(pde & PAGE_PRESENT)) return false;
if (wr && !(pde & PAGE_WRABLE)) return false;
if (!(pde & PAGE_USER)) return false;
size_t pte = mem_get((pde & 0xfffff000) + PTI(addr) * 4);
if (!(pte & PAGE_PRESENT)) return false;
if (wr && !(pte & PAGE_WRABLE)) return false;
if (!(pte & PAGE_USER)) return false;
return true;
}

bool check_memory_permission(const void *_addr, size_t size, bool wr) {
const void *addr = (void *)PADDING_DOWN(_addr, PAGE_SIZE);
const void *end_addr = _addr + size;
for (; addr < end_addr; addr += PAGE_SIZE) {
if (!check_address_permission(addr, wr)) return false;
}
return true;
}

bool check_string_permission(cstr addr) {
if (!check_address_permission(addr, false)) return false;
for (addr++;; addr++) {
if (!((size_t)addr & 0xfff) && !check_address_permission(addr, false)) return false;
if (*addr == '\0') break;
}
return true;
}
10 changes: 5 additions & 5 deletions src/kernel/syscall/mmap.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include <kernel.h>

#define IDX(addr) ((u32)addr >> 12) // 获取 addr 的页索引
#define DIDX(addr) (((u32)addr >> 22) & 0x3ff) // 获取 addr 的页目录索引
#define TIDX(addr) (((u32)addr >> 12) & 0x3ff) // 获取 addr 的页表索引
#define PAGE(idx) ((u32)idx << 12) // 获取页索引 idx 对应的页开始的位置
#define IDX(addr) ((u32)addr >> 12) // 获取 addr 的页索引
#define PDI(addr) (((u32)addr >> 22) & 0x3ff) // 获取 addr 的页目录索引
#define PTI(addr) (((u32)addr >> 12) & 0x3ff) // 获取 addr 的页表索引
#define PAGE(idx) ((u32)idx << 12) // 获取页索引 idx 对应的页开始的位置

extern PageInfo *pages;

Expand All @@ -14,7 +14,7 @@ void *syscall_mmap(void *start, u32 length) {

u32 addr = current_task->cr3;
void *line_addr_start = null;
for (int i = DIDX(0x70000000), c = 0; i < 1024; i++) {
for (int i = PDI(0x70000000), c = 0; i < 1024; i++) {
u32 *pde_entry = (u32 *)addr + i;
u32 p = *pde_entry & (0xfffff000);
for (int j = 0; j < 1024; size_is_2M ? j += 512 : j++) {
Expand Down
16 changes: 15 additions & 1 deletion src/kernel/syscall/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ u32 syscall_heapsize() {
}

static int syscall_vbe_getmode(void **vram, int *width, int *height) {
if (!check_memory_permission(vram, sizeof(void *), true)) task_abort();
if (!check_memory_permission(width, sizeof(int), true)) task_abort();
if (!check_memory_permission(height, sizeof(int), true)) task_abort();
*vram = vbe_frontbuffer;
*width = screen_w;
*height = screen_h;
Expand All @@ -25,6 +28,7 @@ static int syscall_vbe_flip() {
}

static int syscall_vbe_flush(const void *buf) {
if (!check_memory_permission(buf, screen_w * screen_h * 4, false)) task_abort();
return vbe_flush(buf);
}

Expand All @@ -33,6 +37,7 @@ static int syscall_vbe_clear(byte r, byte g, byte b) {
}

static ssize_t syscall_file_size(cstr path) {
if (!check_string_permission(path)) task_abort();
vfs_node_t file = vfs_open(path);
if (file == null) return -1;
size_t size = file->size;
Expand All @@ -41,6 +46,8 @@ static ssize_t syscall_file_size(cstr path) {
}

static ssize_t syscall_load_file(cstr path, void *buf, size_t size) {
if (!check_string_permission(path)) task_abort();
if (!check_memory_permission(buf, size, true)) task_abort();
vfs_node_t file = vfs_open(path);
if (file == null) return -1;
size_t ret = vfs_read(file, buf, 0, size);
Expand All @@ -49,18 +56,25 @@ static ssize_t syscall_load_file(cstr path, void *buf, size_t size) {
}

static ssize_t syscall_save_file(cstr path, const void *buf, size_t size) {
if (!check_string_permission(path)) task_abort();
if (!check_memory_permission(buf, size, false)) task_abort();
vfs_node_t file = vfs_open(path);
if (file == null) return -1;
size_t ret = vfs_write(file, buf, 0, size);
vfs_close(file);
return ret;
}

void syscall_print(cstr s) {
if (!check_string_permission(s)) task_abort();
print(s);
}

void *sycall_handlers[MAX_SYSCALLS] = {
[SYSCALL_EXIT] = &syscall_exit,
[SYSCALL_PUTC] = &putchar,
[SYSCALL_FORK] = &task_fork,
[SYSCALL_PRINT] = &print,
[SYSCALL_PRINT] = &syscall_print,
[SYSCALL_GETHEAP] = &syscall_getheap,
[SYSCALL_HEAPSZ] = &syscall_heapsize,
[SYSCALL_MMAP] = &syscall_mmap,
Expand Down
10 changes: 10 additions & 0 deletions src/kernel/task/mtask.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,16 @@ void task_exit(i32 status) {
abort();
}

void task_abort() {
const var task = current_task;
kassert(task != null);

task_kill(task);

klogf("task_abort error");
abort();
}

i32 task_wait(task_t target) {
kassert(task_current != null);
if (target == null) return -1;
Expand Down

0 comments on commit 233f206

Please sign in to comment.