文章大纲
- 引言
- 一、普通进程访问使用预留内存
- 1、先mmap映射到用户空间后再访问
- 2、使用 /dev/mem 直接访问物理内存
- 2.1、启用 /dev/mem
- 2.2、映射物理地址
- 2.3、用户空间通过dev/mem访问
- 3、通过 UIO(Userspace I/O)框架
- 3.1、UIO 的主要功能
- 3.1.1、内存映射
- 3.1.2、中断处理
- 3.2、设备发现
- 3.3、UIO 的使用步骤
- 3.4、UIO安全增强建议
- 3.4.1、最小化权限:用户程序以非 root 权限运行,结合 setcap 授予必要能力:
- 3.4.2、SELinux/AppArmor:限制 UIO 设备文件的访问策略。
- 3.4.3、内存保护:通过 mprotect 限制用户空间内存区域的读写权限
- 3.5、查看 UIO 设备信息
- 3.6、监控中断
- 4、通过内核驱动程序映射
- 4.1、编写内核驱动
- 4.2、用户空间访问
- 二、内核空间访问(驱动/内核模块)的例子
- 1、映射物理内存到内核虚拟地址
- 2、直接物理地址访问(DMA场景)
- 3、使用 CMA(Contiguous Memory Allocator)
- 三、内存管理策略
- 1、分配方式
- 2、内存保护
- 四、用户进程 vs 内核进程访问预留内存
- 1、访问方式
- 1.1、普通进程
- 1.2、内核进程
- 2、权限控制
- 2.1、普通进程
- 2.2、内核进程
- 3、内存管理
- 3.1、普通进程
- 3.2、内核进程
- 4、安全性
- 4.1、普通进程
- 4.2、内核进程
- 5、使用场景
- 5.1、普通进程
- 5.2、内核进程
- 小结
引言
一、普通进程访问使用预留内存
1、先mmap映射到用户空间后再访问
如果内存区域需要在用户空间访问,可以通过 mmap 将其映射到用户空间。
// 在内核驱动中实现 mmap 方法staticintmy_mmap(structfile*filp,structvm_area_struct*vma){unsignedlongpfn=phys_addr>>PAGE_SHIFT;returnremap_pfn_range(vma,vma->vm_start,pfn,size,vma->vm_page_prot);}// 在用户空间调用 mmapvoid*vaddr=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);在Linux系统中,普通应用程序(用户空间进程)不能直接访问保留内存,因为保留内存通常由内核或专用硬件管理且用户空间与内核空间存在隔离,所以需要先映射然后再访问。
2、使用 /dev/mem 直接访问物理内存
Linux 提供了 /dev/mem 设备文件,允许有权限的进程直接读写物理内存,但是有风险,使用步骤如下:
2.1、启用 /dev/mem
- 内核配置:确保 CONFIG_STRICT_DEVMEM 未启用(或通过 CAP_SYS_RAWIO 权限绕过限制)。
- 内核需启用 CONFIG_DEVMEM 和 CONFIG_STRICT_DEVMEM(默认启用,但可能限制访问)。
- 需要 root 权限或 CAP_SYS_RAWIO 能力。
- 权限控制:限制 /dev/mem 的访问权限(chmod 600 /dev/mem)。
- 直接访问物理内存可能引发缓存一致性问题(需使用 O_SYNC 标志)。
2.2、映射物理地址
intfd=open("/dev/mem",O_RDWR|O_SYNC);void*addr=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,phys_addr);例
# 查看物理内存布局(确认保留地址) sudo cat/proc/iomem # 使用 dd 读取物理内存(示例地址0x10000000) sudo ddif=/dev/mem bs=1count=4skip=$((0x10000000))2>/dev/null|hexdump-C不过也存在一些风险隐患:
- 系统稳定性:误操作可能导致内核崩溃。
- 安全漏洞:恶意程序可能通过 /dev/mem 窃取敏感数据。
- 内核配置限制:CONFIG_STRICT_DEVMEM 默认阻止访问关键内存区域。
2.3、用户空间通过dev/mem访问
#include<sys/mman.h>#include<fcntl.h>#defineRESERVED_PHYS_ADDR0x80000000#defineRESERVED_SIZE0x10000000intmain(){intfd=open("/dev/mem",O_RDWR|O_SYNC);if(fd