linux c之使用mprotect检测内存访问

在Linux中,mprotect()函数可以用来修改一段指定内存区域的保护属性。

函数原型如下:

#include <unistd.h> 
#include <sys/mmap.h> 
int mprotect(const void *start, size_t len, int prot); 

mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。


prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:

1)PROT_READ:表示内存段内的内容可写;

2)PROT_WRITE:表示内存段内的内容可读;

3)PROT_EXEC:表示内存段中的内容可执行;

4)PROT_NONE:表示内存段中的内容根本没法访问。

需要指出的是,锁指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。

如果执行成功,则返回0;如果执行失败,则返回-1,并且设置errno变量,说明具体因为什么原因造成调用失败。错误的原因主要有以下几个:

1)EACCES

该内存不能设置为相应权限。这是可能发生的,比如,如果你 mmap(2) 映射一个文件为只读的,接着使用 mprotect() 标志为 PROT_WRITE。

2)EINVAL

start 不是一个有效的指针,指向的不是某个内存页的开头。

3)ENOMEM

内核内部的结构体无法分配。

4)ENOMEM

进程的地址空间在区间 [start, start+len] 范围内是无效,或者有一个或多个内存页没有映射。

如果调用进程内存访问行为侵犯了这些设置的保护属性,内核会为该进程产生 SIGSEGV (Segmentation fault,段错误)信号,并且终止该进程。

  1. #include <fcntl.h>  
  2. #include <signal.h>  
  3. #include <stdio.h>  
  4. #include <string.h>  
  5. #include <sys/mman.h>  
  6. #include <sys/stat.h>  
  7. #include <sys/types.h>  
  8. #include <unistd.h>  
  9.   
  10. static int alloc_size;  
  11. static char *memory;  
  12.   
  13. int main()  
  14. {  
  15.     int fd;  
  16.     fd = open("/dev/zero", O_RDONLY);  
  17.     alloc_size = getpagesize(); //mmap必须以PAGE_SIZE()为单位映射  
  18.     memory = mmap(NULL, alloc_size, PROT_WRITE, MAP_PRIVATE, fd, 0); //可以在两个进程都映射该文件时实现共享内存  
  19.     close(fd);  
  20.     memory[0] = 1;  
  21.     //mprotect(memory,alloc_size,PROT_NONE); //设置内存为不可访问,禁止访问memory所指内存。  
  22.     memory[0] = 0;  
  23.     printf("all done\n");  
  24.     munmap(memory, alloc_size);  
  25.     return 0;  
  26. }  

  1. #include <fcntl.h>  
  2. #include <signal.h>  
  3. #include <stdio.h>  
  4. #include <string.h>  
  5. #include <sys/mman.h>  
  6. #include <sys/stat.h>  
  7. #include <sys/types.h>  
  8. #include <unistd.h>  
  9.   
  10. static int alloc_size;  
  11. static char* memory;  
  12.   
  13. void segv_handler(int signal_number)  
  14. {  
  15.     printf("find memory accessed!\n");  
  16.     mprotect(memory, alloc_size, PROT_READ | PROT_WRITE);  
  17.       
  18.     printf("set memory read write!\n");  
  19. }  
  20.   
  21. int main()  
  22. {  
  23.     int fd;  
  24.     struct sigaction sa;  
  25.   
  26.     /* 初始化segv_handler为SIGSEGV的句柄。*/  
  27.     memset(&sa, 0, sizeof(sa));  
  28.     sa.sa_handler = &segv_handler;  
  29.     sigaction(SIGSEGV, &sa, NULL);  
  30.   
  31.      /* 使用映射/dev/zero分配内存页。最初映射的内存为只写。*/  
  32.     alloc_size = getpagesize();  
  33.     fd = open("/dev/zero", O_RDONLY);  
  34.     memory = mmap(NULL, alloc_size, PROT_WRITE, MAP_PRIVATE, fd, 0);  
  35.     close(fd);  
  36.     /* 写页来获得一个私有复制。 */  
  37.     memory[0] = 0;  
  38.     printf("memory[0] = 0\n");  
  39.     /* 使内存为不可写。 */  
  40.     mprotect(memory, alloc_size, PROT_NONE);  
  41.     printf("memory[0] = 1 SIGSEGV\n");  
  42.     /* 写分配内存区域。 */  
  43.     memory[0] = 1;  
  44.     printf("memory[0] = 2 ok\n");  
  45.     /* 写分配内存区域。 */  
  46.     memory[0] = 2;  
  47.     /* 所有工作都结束;unmap内存映射。 */  
  48.     printf("all done\n");  
  49.     munmap(memory, alloc_size);  
  50.     return 0;  
  51. }  

输出结果:

memory[0] = 0
memory[0] = 1 SIGSEGV
find memory accessed!
set memory read write!
memory[0] = 2 ok
all done
finish!


上述程序按照如下步骤执行:

  1. 程序为 SIGSEGV 建立一个信号处理句柄。
  2. 程序通过映射 /dev/zero 分配一个内存分页,然后通过写入数据的方式获得一个私有复本。
  3. 程序通过调用带 PROT_NONE 权限的 mprotect 保护了内存。
  4. 当程序在后续执行中写入内存时,Linux 向进程发送 SIGSEGV,这个信号被 segv_handler 句柄接收处理。这个句柄将解除内存保护,因而程序内存访问得以继续。
  5. 当信号句柄执行完成时,程序控制权返回 main 函数,程序将使用 munmap 来释放内存。
原文链接:http://blog.csdn.net/earbao/article/details/51536304
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值