NAME
mprotect — set protection of memory mapping
SYNOPSIS
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
mprotect
将从 addr
开始,长度为 len
的内存区修改为 prot
指定的保护属性
其中, addr
必须是一个内存页的起始地址, len
必须是页的整数倍
prot
可以取值
- PROT_READ, 内存中内容可读
- PROT_WRITE,内存中内容可写
- PROT_EXEC,内存中内容可执行
- PROT_NONE,内存中内容无法访问
如果调用进程内存访问行为侵犯了这些设置的保护属性,内核会为该进程产生 SIGSEGV
guard page
posix threads
While using posix threads in Linux it is done automatically with the guard size attribute that is one page by default
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include <sys/mman.h>
void *threadfn(void *p)
{
int val=100;
printf("thread val address=%lx\n",&val);
sleep(100);
return NULL;
}
int main()
{
int val=100;
printf("main val address=%lx\n",&val);
pthread_t t1,t2,t3;
pthread_create(&t1,NULL,threadfn,NULL);
pthread_create(&t2,NULL,threadfn,NULL);
pthread_create(&t3,NULL,threadfn,NULL);
sleep(100);
pthread_exit(NULL);
return 0;
}
/* Output:
main val address=7ffe2438515c
thread val address=7fdba3989f44
thread val address=7fdba3a8af44
thread val address=7fdba4274f44
*/
文件 /proc/[pid]/maps
2eaaa000-2eaab000 ---p 2eaaa000 00:00 0 //one page(4k) guard page
2eaab000-2ebaa000 rw-p 2eaab000 00:00 0
2ebaa000-2ebab000 ---p 2ebaa000 00:00 0 //one page(4k) guard page
2ebab000-2ecaa000 rw-p 2ebab000 00:00 0
2ecaa000-2ecab000 ---p 2ecaa000 00:00 0 //one page(4k) guard page
2ecab000-2edaa000 rw-p 2ecab000 00:00 0
2edaa000-2edab000 ---p 2edaa000 00:00 0 //one page(4k) guard page
2edab000-2eeaa000 rw-p 2edab000 00:00 0
2eeaa000-2eeab000 ---p 2eeaa000 00:00 0 //one page(4k) guard page
2eeab000-2efaa000 rw-p 2eeab000 00:00 0
2efaa000-2efab000 ---p 2efaa000 00:00 0 //one page(4k) guard page
posix threads
提供一组接口
NAME
pthread_attr_setguardsize, pthread_attr_getguardsize - set/get guard size attribute in thread attributes object
SYNOPSIS
#include <pthread.h>
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize);
Compile and link with -pthread.
NOTES
A guard area consists of virtual memory pages that are protected to prevent read and write access. If a thread
overflows its stack into the guard area, then, on most hard architectures, it receives a SIGSEGV signal, thus noti‐
fying it of the overflow.
stack overflow
时会触发 SIGSEGV
others memory
But what about memory that is not located in the stack like dynamic allocation or buffers in BSS/DATA sections? here you can use mprotect to create that guard area
mprotect can be used to change MMU permissions on any mapped memory
One point to notice is that the buffer must be aligned to a page boundary so we can’t allocate it using malloc. we can use memalign or aligned_alloc but the best way in this case is to call mmap directly and not use any heap. mmap returns page(s) and if we use it with MAP_ANONYMOUS we get memory from the kernel
p1=mmap(0,0x20000,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
mprotect(p1+page_size,page_size,PROT_NONE);
mprotect(p1+0x1f000,0x1000,PROT_NONE);
pthread_attr_setstack(&attr,p1+0x1000,0x1e000);
pthread_create(&t1,&attr,threadfn1,NULL);