JOS 用户态page fault保护处理机制分析
2015-04-25 18:38
288 查看
JOS 用户态page fault保护处理机制分析
常常会在用户态触发page fault,如果直接让其因为page fault跌入内核触发panic目测是不是"太残忍了"
你想想,一个刚学会写C程序的童鞋,就经常干 *(int *)0x00.
当然,我只是比较赤果果的指出这种问题而已,这位同学可能经常用各种指针,然后指针为初始化亦或等于NULL的时候,对其进行赋值或解引用.总不至于让一个刚学C的人就把整个系统都给挂了吧?恩.我们需要一种保护机制.
可以在用户态触发page fault,跌入内核时,我们可以做点"手脚",不要让他触发panic.
内核稍作处理,程序执行流返回到用户,并提示用户"同学,对非法的地址这么读写都是不对的哇"[ core dump大家一定都很熟悉了...哈哈]
好吧需求背景说完了,进入正题.
faultdie.c用户程序
集中精力关注,umain函数.
无非就是在对一个非法地址赋值前进行了一点"小动作"--set_pgfault_handler.
这里传入了一个普通的函数地址handler.我们看看set_pgfault_handler 做了什么
全局变量 _pgfault_handler是个函数指针.初始全局变量被初始化为0.
这个函数第一次运行的时候,会为当前进程 thisenv申请一页的内存,把这一页内存,映射到虚拟地址 va.
而后,通过sys_env_set_pgfault_upcall设置了_pgfault_upcall(一个汇编代码的入口)为返回地址.
最后把 _pgfault_handler设置为 handler.
用户触发page fault异常之后,跌入内核态,
struct Trapframe储存在内核栈上.
_alltraps会把寄存器各种压栈,然后调用trap(),进而调用trap_dispatch()
于是就会根据触发trap的是什么类型的异常来进行相依的处理,这里是Page fault.
于是,开始调用page_fault_handler.
tf指针还是指向刚刚我们压栈好的内核栈上struct Trapframe的首地址处.
在page_fault_handler内部.首先会检测我们是不是已经申请了用户异常栈的地址(翻到这篇博客看前面set_pgfault_handler里怎么申请的).
只要申请好了用户异常栈,于是就开始各种寄存器的拷贝.把当前内核栈上面的struct Trapframe拷贝到异常栈上去.
反正内核态有权限嘛~
细心的话你会发现,这里的拷贝是夸段的,内核堆栈段的数据拷贝到用户的异常栈上.因为内核有读写权限~
把utf指向的用户异常栈的栈顶指针赋值给当前内核栈内struct Trapframe的tf_esp成员,这个家伙会在之后内核弹栈切换进程的时候赋值给esp寄存器,进而设置好用户态的栈顶指针!那时候栈的切换就完成了.
env_run开始重新运行当前进程.env_run会调用 env_pop_tf()把内核栈上的struct Trapframe弹栈.切换进程!
我们来测试,就是切换进程后的栈顶是不是在UXSTACKTOP ( 0xeec00000)下面
测试:
我们把断点设置在handler的入口.看 esp在 UXSTACKTOP下面.
常常会在用户态触发page fault,如果直接让其因为page fault跌入内核触发panic目测是不是"太残忍了"
你想想,一个刚学会写C程序的童鞋,就经常干 *(int *)0x00.
当然,我只是比较赤果果的指出这种问题而已,这位同学可能经常用各种指针,然后指针为初始化亦或等于NULL的时候,对其进行赋值或解引用.总不至于让一个刚学C的人就把整个系统都给挂了吧?恩.我们需要一种保护机制.
可以在用户态触发page fault,跌入内核时,我们可以做点"手脚",不要让他触发panic.
内核稍作处理,程序执行流返回到用户,并提示用户"同学,对非法的地址这么读写都是不对的哇"[ core dump大家一定都很熟悉了...哈哈]
好吧需求背景说完了,进入正题.
faultdie.c用户程序
集中精力关注,umain函数.
无非就是在对一个非法地址赋值前进行了一点"小动作"--set_pgfault_handler.
这里传入了一个普通的函数地址handler.我们看看set_pgfault_handler 做了什么
全局变量 _pgfault_handler是个函数指针.初始全局变量被初始化为0.
这个函数第一次运行的时候,会为当前进程 thisenv申请一页的内存,把这一页内存,映射到虚拟地址 va.
而后,通过sys_env_set_pgfault_upcall设置了_pgfault_upcall(一个汇编代码的入口)为返回地址.
最后把 _pgfault_handler设置为 handler.
用户触发page fault异常之后,跌入内核态,
struct Trapframe储存在内核栈上.
_alltraps会把寄存器各种压栈,然后调用trap(),进而调用trap_dispatch()
于是就会根据触发trap的是什么类型的异常来进行相依的处理,这里是Page fault.
于是,开始调用page_fault_handler.
tf指针还是指向刚刚我们压栈好的内核栈上struct Trapframe的首地址处.
在page_fault_handler内部.首先会检测我们是不是已经申请了用户异常栈的地址(翻到这篇博客看前面set_pgfault_handler里怎么申请的).
只要申请好了用户异常栈,于是就开始各种寄存器的拷贝.把当前内核栈上面的struct Trapframe拷贝到异常栈上去.
反正内核态有权限嘛~
细心的话你会发现,这里的拷贝是夸段的,内核堆栈段的数据拷贝到用户的异常栈上.因为内核有读写权限~
把utf指向的用户异常栈的栈顶指针赋值给当前内核栈内struct Trapframe的tf_esp成员,这个家伙会在之后内核弹栈切换进程的时候赋值给esp寄存器,进而设置好用户态的栈顶指针!那时候栈的切换就完成了.
env_run开始重新运行当前进程.env_run会调用 env_pop_tf()把内核栈上的struct Trapframe弹栈.切换进程!
我们来测试,就是切换进程后的栈顶是不是在UXSTACKTOP ( 0xeec00000)下面
测试:
我们把断点设置在handler的入口.看 esp在 UXSTACKTOP下面.
相关文章推荐
- Linux内核IP Queue机制的分析(二)——用户态处理并回传数据包
- Linux内核IP Queue机制的分析(二)——用户态处理并回传数据包
- Linux内核IP Queue机制的分析(二)——用户态处理并回传数据包
- Linux kernel 分析之二十二:内存管理-page fault处理流程
- PHP中的错误处理、异常处理机制分析
- android的消息处理机制(图+源码分析)——Looper,Handler,Message
- Android应用程序键盘(Keyboard)消息处理机制分析(11)
- Android应用程序键盘(Keyboard)消息处理机制分析(27)
- 从源代码分析Android-Universal-Image-Loader的缓存处理机制
- android的消息处理机制(图+源码分析)——Looper,Handler,Message
- SEAndroid安全机制对Binder IPC的保护分析
- Android的消息处理机制(图+源码分析)——Looper,Handler,Message
- 分析Hibernate的事务处理机制
- Handler+Message+MessageQuque+Looper 异步加载类 消息处理机制 分析
- 关于使用Axis2 webservice 处理Fault响应时抛org.apache.axis2.AxisFault的分析
- android的消息处理机制(图+源码分析)——Looper,Handler,Message
- 从源代码分析Android-Universal-Image-Loader的缓存处理机制
- linux 内核处理缺页异常函数:do_page_fault ,2.4.0版
- [置顶] Android开发知识(八):Android事件处理机制:事件分发、传递、拦截、处理机制的原理分析(中)
- android的消息处理机制(图+源码分析)——Looper,Handler,Message