页式存储管理机制通过页面目录和页面表将每个线性地址转换成物理地址,当遇到下面几种情况就会使CPU产生一次缺页中断,从而执行预定的页面异常处理程序:

  ① 相应的页面目录或页表项为空,也就是该线性地址与物理地址的关系还没建立或者已经撤销

  ② 相应的物理页面不在内存中

  ③ 指令规定的访问方式与页面的权限不符

  我们假设一个情景,当我们的用户程序将一个打开的文件通过mmap()映射到内存,然后又通过munmap()撤销映射。在撤销一个映射区间时,常常会在虚存地址空间中留下一个空洞,而相应的地址则不应继续使用了,但是,程序中可能会有错误继续访问这个已经撤销的区域,这时候,一次因越界访问一个无效地址而引起映射失败,从而产生了一次页面出错异常。 我们假设CPU已经运行到页面异常服务程序的主体函数do_page_fault()的入口处

 1 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
2 {
3 struct task_struct *tsk;
4 struct mm_struct *mm;
5 struct vm_area_struct * vma;
6 unsigned long address;
7 unsigned long page;
8 unsigned long fixup;
9 int write;
10 siginfo_t info;
11
12 /* get the address */
13 __asm__("movl %%cr2,%0":"=r" (address));
14
15 tsk = current;
16
17 /*
18 * We fault-in kernel-space virtual memory on-demand. The
19 * 'reference' page table is init_mm.pgd.
20 *
21 * NOTE! We MUST NOT take any locks for this case. We may
22 * be in an interrupt or a critical region, and should
23 * only copy the information from the master page table,
24 * nothing more.
25 */
26 if (address >= TASK_SIZE)
27 goto vmalloc_fault;
28
29 mm = tsk->mm;
30 info.si_code = SEGV_MAPERR;
31
32 /*
33 * If we're in an interrupt or have no user
34 * context, we must not take the fault..
35 */
36 if (in_interrupt() || !mm)
37 goto no_context;
38
39 down(&mm->mmap_sem);
40
41 vma = find_vma(mm, address);
42 if (!vma)
43 goto bad_area;
44 if (vma->vm_start <= address)
45 goto good_area;
46 if (!(vma->vm_flags & VM_GROWSDOWN))
47 goto bad_area;

  此函数参数,一个是pt_regs 结构指针regs,它指向异常发生前夕 CPU 中各寄存器内容的一份副本,这是由内核的中断响应机制保存下来的“现场”,另一个参数error_code则指明映射失败的具体原因。

  首先是一行汇编代码,引文当i386 CPU 产生“页面错”异常时,CPU 将导致映射失败的线性地址放在控制寄存器CR2中,这行代码的作用就是读取CR2的内容到变量address。

  然后是通过宏操作current来取得当前进程的task_struct结构的地址。

  接下来,需要检测两个特殊情况,一个特殊情况是in_interrupt()返回非0,说明映射的失败发生在某个中断服务程序中,因而与当前进程毫无关系,另一个特殊情况是当前进程的mm指针为空,也就是该进程尚未建立映射,也就不可能与当前进程有关。若mm指针为空,且in_interrupt返回非0,,那这次异常发生在什么地方呢?其实还是在某个中断/异常的服务程序中,只不过不在in_interrupt()能检测到的范围而已。

  以下有互斥的要求了,从down()返回后就不会有别的进程来打扰了。

  在知道了发生映射失败的地址以及所属的进程以后,接下来应该要搞清楚的是这个地址是否落在某个已建立起映射的区间,或者进一步具体指出在哪个区间。事实正是这样,这就是find_vma()所做的事。以前讲过,find_vma()试图在一个虚存空间中找出结束地址大于给定地址的第一个区间,如果找不到的话,那么本次页面异常就必定是因越界访问而引起,那么,在什么情况下会找不到呢?回忆一下内核对用户虚存空间的使用,堆栈在用户区的顶部,从上而下扩展,而进程的代码和数据都是自底向上分配空间。如果没有一个区间的结束地址高于给定的地址,那就说明这个地址是在堆栈之上,也就是3G字节以上了,要从用户空间访问内核空间,当然是越界了,然后就转向bad_area,发生映射失败的地址对应下图的①

  如果找到了这么一个区间,而且其起始地址又不高于给定的地址,那就说明给定的地址恰好落在这个区间,这样,映射肯定已经建立,所以就转向good_area去进一步检查失败的原因,发生映射失败的地址对应下图的②或⑤

  剩下的情况就是给定地址正好落在两个区间当中的空洞里,也就是该地址所在页面的映射尚未建立或已经撤销,在用户虚存空间中,可能有两种不同的空洞,第一种空洞只能有一个,那就是堆栈区以下的那个大空洞,它代表着工动态分配而仍未分配出去的空间。但是怎样知道这个地址是落在这个空洞里呢?我们知道,堆栈是向下扩展的,如果find_vma()找到的区间是堆栈区间,那么它的vm_flags中应该有标志位VM_GROWSDOWN。要是该标志位为0的话,那就说明空洞上方的区间并非堆栈区,说明这个空洞是因为一个映射区间被撤销而留下的,或者是在建立映射时跳过了一块地址,发生映射失败的地址对应下图的④

下面,我们就随着goto语句转向bad_area,

【do_page_fault】

 1 bad_area:
2 up(&mm->mmap_sem);
3
4 bad_area_nosemaphore:
5 /* User mode accesses just cause a SIGSEGV */
6 if (error_code & 4) {
7 tsk->thread.cr2 = address;
8 tsk->thread.error_code = error_code;
9 tsk->thread.trap_no = 14;
10 info.si_signo = SIGSEGV;
11 info.si_errno = 0;
12 /* info.si_code has been set above */
13 info.si_addr = (void *)address;
14 force_sig_info(SIGSEGV, &info, tsk);
15 return;
16 }

  当error_code的bit2为1时,表示失败是当CPU处于用户模式时发生的,这与我们的情景相符,所以控制将进入第6行,在那里,对当前进程的task_struct结构内的一些成员进行一些设置以后,就向该进程发出一个强制的“信号”SIGSEGV,至此,本次例外服务程序就结束了。

  每次中断/异常返回之前,都要检查当前进程是否有悬而未决的信号需要处理,然后,内核根据这些待处理的信号的性质以及进程本身的选择决定怎么办,而对于SIGSEGV的处理结果是在该进程的显示屏上显示“Segment Fault”提示,然后结束进程

linux 内核源代码情景分析——越界访问的更多相关文章

  1. Linux内核源代码情景分析系列

    http://blog.sina.com.cn/s/blog_6b94d5680101vfqv.html Linux内核源代码情景分析---第五章 文件系统  5.1 概述 构成一个操作系统最重要的就 ...

  2. Linux内核源代码情景分析-fork()

    父进程fork子进程: child = fork() fork经过系统调用.来到了sys_fork.具体过程请參考Linux内核源码情景分析-系统调用. asmlinkage int sys_fork ...

  3. linux 内核源代码情景分析——用户堆栈的扩展

    上一节中,我们浏览了一次因越界访问而造成映射失败从而引起进程流产的过程,不过有时候,越界访问时正常的.现在我们就来看看当用户堆栈过小,但是因越界访问而"因祸得福"得以伸展的情景. ...

  4. linux 内核源代码情景分析——地址映射的全过程

    linux 内核采用页式存储管理.虚拟地址空间划分成固定大小的"页面",由MMU在运行时将虚拟地址映射成某个物理内存页面中的地址.页式内存管理比段式内存管理有很多好处,但是由于In ...

  5. linux 内核源代码情景分析——linux 内存管理的基本框架

    386 CPU中的页式存管的基本思路是:通过页面目录和页面表分两个层次实现从线性地址到物理地址的映射.这种映射模式在大多数情况下可以节省页面表所占用的空间.因为大多数进程不会用到整个虚存空间,在虚存空 ...

  6. linux 内核源代码情景分析——linux 内核源代码中的C语言代码

    linux 内核的主体是以GNU的C语言编写的,GNU为此提供了编译工具gcc.GNU对C语言本身作了不少扩充. 1) gcc 从 C++ 语言中吸收了"inline"和" ...

  7. Linux内核源代码情景分析-中断半

    一.中断初始化 1.中断向量表IDT初始化 void __init init_IRQ(void) { int i; #ifndef CONFIG_X86_VISWS_APIC init_ISA_irq ...

  8. linux 内核源代码情景分析——几个重要的数据结构和函数

    页面目录PGD.中间目录PMD和页面表PT分别是由表项pgd_t.pmd_t和pte_t构成的数组,而这些表项都是数据结构 1 /* 2 * These are used to make use of ...

  9. linux 内核源代码情景分析——linux 内核源码中的汇编语言代码

    1. 用汇编语言编写部分核心代码的原因: ① 操作系统内核中的底层程序直接与硬件打交道,需要用到一些专用的指令,而这些指令在C语言中并无对应的语言成分: ② CPU中的一些特殊指令也没有对应的C语言成 ...

随机推荐

  1. Vue3的其他属性和API函数

    customRef() 自定义Ref函数实现Ref()的相关功能 1 <script> 2 import { ref customRef} from 'vue' 3 4 function ...

  2. PHP没有定时器?

    确实,PHP没有类似于JS中的setInterval或者setTimeout这样的原生定时器相关的函数.但是我们可以通过其他方式来实现,比如使用declare. 先来看看是如何实现的,然后我们再好好学 ...

  3. 【tp3.2】根据不同域名来加载不同的配置文件

    遇到问题: 最近遇到一个需求,需要多个公众号使用同一个项目,这就导致了不同公众号访问的数据库和公众号配置不同. 解决思路: 查看文档:http://document.thinkphp.cn/manua ...

  4. win10系统移动热点使用技巧

    win10系统是自动移动热点功能,在平时测试的时候,有时需要进行手机抓包,需要手机和电脑处于同一网络当中,这时可以开启热点使用. 如何开启移动热点? 直接搜索"移动热点" 但是如果 ...

  5. 配置阿里云maven

    在安装好Maven之后,默认的~/.m2目录下是没有maven仓库配置文件settings.xml的,默认使用的是官方的仓库,访问速度会非常慢,我们需要配置下国内的仓库. 创建~/.m2/settin ...

  6. python编码问题:UnicodeDecodeError: 'gbk' codec can't decode

    在获取yaml文件数据时,提示:UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 2: illegal multib ...

  7. CF235C-Cyclical Quest【SAM】

    正题 题目链接:https://www.luogu.com.cn/problem/CF235C 题目大意 一个文本串\(s\).询问\(n\)个匹配的本质不同的循环同构在文本串中出现了几次. 解题思路 ...

  8. Superedge的新特性和未来之路

    作者 王冬,腾讯云高级研发工程师,专注于Kubernetes.容器等云原生领域,SuperEdge 核心开发人员,现负责腾讯云边缘容器TKE Edge私有化相关工作. 背景 2021年9月27号,,在 ...

  9. 基于 Ubuntu 21.04 BPF 开发环境全攻略

    本文地址:https://www.ebpf.top/post/ubuntu_2104_bpf_env 1. 系统安装 1.1 Vagrant Vagrant 是一款用于构建及配置虚拟开发环境的软件,基 ...

  10. (googlechrome)未知错误导致安装失败,如果googlechrome....

    ​https://jingyan.baidu.com/article/ea24bc39ffb699da63b33147.html#5827690-tsina-1-63512-fe183374908e7 ...