4.系统调用如何安全地获取参数
5.系统调用如何安全地获取参数
直接传递给kernel数据的地址(指针)?,
- 内核和用户的页表不同,不能直接访问用户地址
- 可能会传递内核内存地址,直接访问就是安全漏洞
因此内核不能使用普通指令从用户提供的地址加载或存储。 内核实现了一些函数,可以安全地在用户提供的地址之间传输数据。
fetchstr
是一个例子(kernel/syscall.c:25)
。文件系统调用,如exec
,就使用fetchstr
从用户空间检索字符串文件名参数。
方法就是利用用户页表对地址进行访问,将数据复制到一个临时创建的数组中使用,这样如果地址不合法,用户页表是无法解析的
5.1 fetchstr()
int fetchstr(uint64 addr, char *buf, int max)
{
struct proc *p = myproc();
//将user pagetable传递过去
if(copyinstr(p->pagetable, buf, addr, max) < 0)
return -1;
return strlen(buf);
}
5.2 copyinstr()
int copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
{
uint64 n, va0, pa0;
int got_null = 0;
while(got_null == 0 && max > 0){
va0 = PGROUNDDOWN(srcva);
pa0 = walkaddr(pagetable, va0);
if(pa0 == 0)
return -1;
n = PGSIZE - (srcva - va0);
if(n > max)
n = max;
char *p = (char *) (pa0 + (srcva - va0));
while(n > 0){
if(*p == '\0'){
*dst = '\0';
got_null = 1;
break;
} else {
*dst = *p;
}
--n;
--max;
p++;
dst++;
}
srcva = va0 + PGSIZE;
}
if(got_null){
return 0;
} else {
return -1;
}
}