mm/mprotect.c
本模块只提供一个系统调用,而无其他接口。这个系统调用就是sys_mprotect.
系统调用sys_mprotect(unsigned long start, size_t len, unsigned long prot)
改变地址范围[start,addr+len-1]涉及到的物理页面的保护方式。对于i386就是
改变pte中的__pgprot。
其中prot可用的参数有:
PROT_WRITE/PROT_READ/PROT_EXEC
PROT_NONE:此段内存不能被访问.
新设置的属性会完全取代现有属性,而不是叠加到现有属性上.
此系统调用实现起来也不复杂,思路也常见了:遍历涉及到的vma,根据属性的改
变进行fixup(这个东西看到好几次了),同时设置所涉及之pte的prot属性.
不再进行更详尽的分析了,简单看看函数:
asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
{
unsigned long nstart, end, tmp;
struct vm_area_struct * vma, * next;
int error = -EINVAL;
if (start & ~PAGE_MASK) return -EINVAL;
len = PAGE_ALIGN(len); end = start + len;
if (end < start)
return -EINVAL;
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) return -EINVAL;
if (end == start)
return 0;
down(¤t->mm->mmap_sem);
vma = find_vma(current->mm, start); error = -EFAULT;
if (!vma || vma->vm_start > start)
goto out;
for (nstart = start ; ; ) {
unsigned int newflags;
newflags = prot | (vma->vm_flags & ~(PROT_READ | PROT_WRITE | PROT_EXEC));
if ((newflags & ~(newflags >> 4)) & 0xf) { error = -EACCES;
break;
}
if (vma->vm_end >= end) { error = mprotect_fixup(vma, nstart, end, newflags);
break;
}
tmp = vma->vm_end;
next = vma->vm_next;
error = mprotect_fixup(vma, nstart, tmp, newflags);
if (error)
break;
nstart = tmp;
vma = next;
if (!vma || vma->vm_start != nstart) {
error = -EFAULT;
break;
}
}
out:
up(¤t->mm->mmap_sem);
return error;
}
次函数使用的fixup函数,以及改变pte的prot的部分不再做详细分析,重点注意
下面几个问题:
1)pmd_bad
static inline void change_pte_range(pmd_t * pmd, unsigned long address,
unsigned long size, pgprot_t newprot)
{
pte_t * pte;
unsigned long end;
if (pmd_none(*pmd))
return;
if (pmd_bad(*pmd)) { pmd_ERROR(*pmd); pmd_clear(pmd); return; }
.....
}
2.vm flags 到pte prot的转化表
static int mprotect_fixup(struct vm_area_struct * vma,
unsigned long start, unsigned long end, unsigned int newflags)
{
pgprot_t newprot;
int error;
if (newflags == vma->vm_flags)
return 0;
newprot = protection_map[newflags & 0xf];
.....
}
}