Linux内存mprotect读写,mprotect笔记

用户态mprotect的定义

int mprotect(const void *addr, size_t len, int prot);

其中:addr --- 起始地址

len   ----addr开始的一块内存的大小

prot  ---- 期望设置的内存属性,取值是PROT_READ, PROT_WRITE, PROT_EXEC,  PROT_NONE 这些bit的组合

SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,

unsigned long, prot)

{

unsigned long vm_flags, nstart, end, tmp, reqprot;

struct vm_area_struct *vma, *prev;

int error = -EINVAL;

/*  取出prot的GROWSDOWN GROWSUP 的属性后, 将prot里面的这两个bit掩掉 */

const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);

prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP);

if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */  /* GROWSDOWN GROWSUP两个属性是互斥的,不能同时存在  */

return -EINVAL;

if (start & ~PAGE_MASK)  /* 起始地址需要按页对齐 */

return -EINVAL;

if (!len)            /* 长度不能为0 */

return 0;

len = PAGE_ALIGN(len);  /* 长度需要按页对齐 */

end = start + len;

if (end <= start)

return -ENOMEM;

#ifdef CONFIG_PAX_SEGMEXEC

if (current->mm->pax_flags & MF_PAX_SEGMEXEC) {

if (end > SEGMEXEC_TASK_SIZE)

return -EINVAL;

} else

#endif

if (end > TASK_SIZE)

return -EINVAL;

if (!arch_validate_prot(prot)) /* 检查prot */

return -EINVAL;

reqprot = prot;

/*

* Does the application expect PROT_READ to imply PROT_EXEC:

*/

/* 如果程序有READ_IMPLIES_EXEC标志,则修改prot具备EXEC标志 */

if ((prot & (PROT_READ | PROT_WRITE)) && (current->personality & READ_IMPLIES_EXEC))

prot |= PROT_EXEC;

/* 将PROT_READ, PROT_WRITE, PROT_EXEC 这些标志位转换为VM_READ, VM_WRITE, VM_EXEC */

vm_flags = calc_vm_prot_bits(prot);

down_write(¤t->mm->mmap_sem);

vma = find_vma_prev(current->mm, start, &prev);

error = -ENOMEM;

if (!vma)

goto out;

if (unlikely(grows & PROT_GROWSDOWN)) {

if (vma->vm_start >= end)

goto out;

start = vma->vm_start;

error = -EINVAL;

if (!(vma->vm_flags & VM_GROWSDOWN))

goto out;

}

else {

if (vma->vm_start > start)

goto out;

if (unlikely(grows & PROT_GROWSUP)) {

end = vma->vm_end;

error = -EINVAL;

if (!(vma->vm_flags & VM_GROWSUP))

goto out;

}

}

if (start > vma->vm_start)

prev = vma;

#ifdef CONFIG_PAX_MPROTECT

if (current->mm->binfmt && current->mm->binfmt->handle_mprotect)

current->mm->binfmt->handle_mprotect(vma, vm_flags);

#endif

/* 到此vma已经找到 */

for (nstart = start ; ; ) {

unsigned long newflags;

/* Here we know that  vma->vm_start <= nstart < vma->vm_end. */

/* vm_flags 是prot装换而来,是应用要求达到的页属性,包括读,写,执行属性

vma->vm_flags 是页面当前具备的属性

(vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC) 是要把页面当前属性的读,写,执行三bit掩掉

newflags =  vm_flags | (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC))

是把应用要求的读写执行属性结合vma->vm_flags 记录到newflags

*/

newflags = vm_flags | (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));

/* newflags >> 4 shift VM_MAY% in place of VM_% */

/*

#define VM_READ        0x00000001    /* currently active flags */

#define VM_WRITE    0x00000002

#define VM_EXEC        0x00000004

#define VM_SHARED    0x00000008

/* mprotect() hardcodes VM_MAYREAD >> 4 == VM_READ, and so for r/w/x bits. */

#define VM_MAYREAD    0x00000010    /* limits for mprotect() etc */

#define VM_MAYWRITE    0x00000020

#define VM_MAYEXEC    0x00000040

#define VM_MAYSHARE    0x00000080

VM_READ VM_WRITE  VM_EXEC 是 0, 1, 2 bit

VM_MAYREAD VM_MAYWRITE  VM_MAYEXEC 是 4, 5, 6bit

将newflags 右移四位, 实际上0-3bit上显示的是VM_MAY% 的属性;

比如newflags的RWX属性是  1       1      1    这个属性是目标属性

而May_% 属性是       1       1      0    这个属性是是否允许设置的属性

May_% 属性取反     0       0      1

--------------------------------------------------------------------------------------------

RWX属性&May_%属性取反     0        0      1             bit 为1的属性表示矛盾的属性,即希望使能某属性而该属性不允许被使能

*/

if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) {

if (prot & (PROT_WRITE | PROT_EXEC)) /* 如果write和exec属性要求设置,而不允许设置,这里要log */

gr_log_rwxmprotect(vma);

error = -EACCES;

goto out;

}

/* 对于heap和stack, 目前的做法是允许设置EXEC权限,但是要在log里面记录一下 */

#ifdef CONFIG_PAX_MPROTECT_WARNONLY

if (current->mm->pax_flags & MF_PAX_MPROTECT) {

if (prot & PROT_EXEC) {

/* warning only on heap */

if (vma->vm_start <= current->mm->brk &&

vma->vm_end >= current->mm->start_brk)

gr_log_rwxmprotect(vma);

/* warning only on stack */

else if (vma->vm_flags & (VM_GROWSDOWN | VM_GROWSUP))

gr_log_rwxmprotect(vma);

}

}

#endif

if (!gr_acl_handle_mprotect(vma->vm_file, prot)) {

error = -EACCES;

goto out;

}

error = security_file_mprotect(vma, reqprot, prot);

if (error)

goto out;

tmp = vma->vm_end;

if (tmp > end)

tmp = end;

error = mprotect_fixup(vma, &prev, nstart, tmp, newflags);

if (error)

goto out;

track_exec_limit(current->mm, nstart, tmp, vm_flags);

nstart = tmp;

if (nstart < prev->vm_end)

nstart = prev->vm_end;

if (nstart >= end)

goto out;

vma = prev->vm_next;

if (!vma || vma->vm_start != nstart) {

error = -ENOMEM;

goto out;

}

}

out:

up_write(¤t->mm->mmap_sem);

return error;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值