`
memorymyann
  • 浏览: 271835 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

linux学习三越界访问

阅读更多

之前看过了内存管理的数据结构,下面通过越界访问来熟悉下这些数据结构。(之前一直没有让大家去下载内核源代码,因为我列的比较详细,接下来的东西,大家自己去http://www.kernelnewbies.org/下载内核源代码,然后结合起来看)

页式存储管理通过页面目录和页面表将线性地址转换成物理地址。如果在这个过程中遇到某种阻碍。这种阻碍的情况有很多,我们举个实际例子,我们通过系统调用mmap()将一个已打开文件印射到内存,然后又撤销,在虚存空间上留下了个空洞,程序又再次访问这个内存,从而就会导致失败。出错后,会产生一个页面出错异常。CPU就运行到了页面出错异常程序的do_page_fault()的入口处。代码定义于arch/i386/mm/fault.c

代码很长,我就不贴了,我只贴我们所发生的情况而会执行到的代码。

fastcall void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)//越界访问,程序入口。reges中断前,CPU各寄存器副本,error_code详细原因,看英文注释
程序运行此函数,第一个执行的语句是address = read_cr2(); //也可能是__asm__("movl %%cr2, %0":"=r" (address));但2者效果都是将CPU的CR2寄存器的内容读取到address中,CPU将导致映射失败的线性地址放到了寄存器cr2,因此address便是导致映射失败的线性地址。

接下来执行的语句是:tsk = current;其中current是个宏操作,将当前进程的进程控制块(PCB)task_struct返回。有了失败的线性地址和进程这些信息后,我们就可以开始下面的操作了。

我们之前说过我们的映射失败是由于我们撤销了这个内存,之后又再次访问。该方法之间的很多代码是检测是否其它原因造成的映射失败,这里就不讨论了,我们代码将会执行到mm = tsk->mm;看上次数据结构我们便知道mm指向的是映射失败进程的虚存空间描述的数据结构mm_struct。接下来我们程序便会运行到if (!down_read_trylock(&mm->mmap_sem)),这里就是进程间互斥访问mm_struct,前面的数据结构中已经提到了mmap_sem 的作用,判断没人访问就进入mm_struct资源,同时对该资源加锁。

接下来运行到vma = find_vma(mm, address);这个便是寻找虚存空间中第一个地址大于给定地址address的区间。找到后返回虚存区间,对应的数据结构就是vm_area_struct。当然可能存在找不到的情况,不过我们目前这种情况不属于这种,暂不讨论。

接下来我们找到了虚存区间vma,说明我们的地址印射已经建立起来,那么代码就会执行到

if (!vma) //这个就是我们所说的没有找到虚存空间的情况了,我们目前不属于这种情况
        goto bad_area;
if (vma->vm_start <= address)   //已经找到了vma,且vma的起始地址小于等于映射失败地址,就表示该地址落在了这个虚存区间内,我们就进一步转向good_area中去查找原因。这种情况映射已经建立,不是我们目前发生的情况
        goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
        goto bad_area;

我们详细说下第3个 if条件,我们上面的数据结构说到了vm_flags这个项,用于保存区间权限和其它一些属性。vm->flags&VM_GROWSDOW为0表示找到的区间并非堆栈区,我们的情况属于这种情形。这里插下堆栈区,他是高地址上起始的,自上向下扩展。我们发生的情况目前处于读入文件内容,放到数据段,后来又撤销了。这样释放了内存。现在再去访问这个地址,地址很自然是在2个区间之间的那块空洞中。因此我们代码便进入了bad_area中。

bad_area:
    up_read(&mm->mmap_sem); //不需要对mm进行互斥操作了,因此,释放他

bad_area_nosemaphore:
    /* User mode accesses just cause a SIGSEGV */
    if (error_code & 4) {
        /*
         * Valid to do another page fault here because this one came
         * from user space.
         */
        if (is_prefetch(regs, address, error_code))
            return;

        tsk->thread.cr2 = address;
        /* Kernel addresses are always protection faults */
        tsk->thread.error_code = error_code | (address >= TASK_SIZE);
        tsk->thread.trap_no = 14;
        force_sig_info_fault(SIGSEGV, si_code, address, tsk);
        return;
    }

error_code中保存的是失败的详细信息,作者为它加了注释,我们看下注释:

/*
 * error_code:
 *    bit 0 == 0 means no page found, 1 means protection fault
 *    bit 1 == 0 means read, 1 means write
 *    bit 2 == 0 means kernel, 1 means user-mode
 *    bit 3 == 1 means use of reserved bit detected
 *    bit 4 == 1 means fault was an instruction fetch
 */

我们的情况是用户模式下发生的,因此bit2=1,因此我们的代码运行便会进入到 if (error_code & 4)内部,内部代码大致执行的情况是设置task_struct,向该进程发出一个软中断,至此,一次例外服务程序便结束了。

如果有错误或者问题的话,请留言指出。

分享到:
评论

相关推荐

    嵌入式Linux内存与性能详解

    嵌入式Linux系统在各种设备和应用中广泛使用,其...通过学习《嵌入式Linux内存与性能详解》,开发者可以更好地理解和掌握嵌入式Linux环境下的内存管理技术,从而提升系统效率和稳定性,满足各类嵌入式设备的严格要求。

    深入理解linux内核第三版中文版part1

    4. **地址空间布局**:了解不同类型的内存区域(堆、栈、共享库、堆栈等)在地址空间中的分布,以及如何保护它们防止越界访问。 5. **内存权限**:读、写、执行权限是如何在页表中设置的,以及如何通过`mprotect`...

    嵌入式Linux上的C语言编程实践

    在嵌入式Linux系统中,C语言是一种...通过深入学习和实践`《嵌入式Linux上的C语言编程实践》.pdf`,开发者能掌握如何在嵌入式Linux环境下有效地使用C语言,编写出高效、可靠的系统级代码,以满足各种嵌入式应用的需求。

    易语言源码易语言linux内存操作源码.rar

    易语言在Linux中进行内存操作,需要了解这种分页模型,以便正确地分配、释放和访问内存。 2. **动态内存分配**:在易语言中,使用`malloc`和`free`函数进行动态内存分配和释放。`malloc`用于申请内存空间,`free`则...

    深入理解linux内核中文第三版-第9章

    7. **内存保护**:内核通过页表项的权限位实现内存保护,防止进程意外修改敏感区域或越界访问。例如,只读、读写和执行权限的设置。 8. **交换和交换文件**:当物理内存不足时,内核会将不活跃的页面交换到磁盘上的...

    cuda.rar_cuda_linux cuda_minimal

    它可以捕获内存错误,如内存泄漏、未初始化的内存访问和越界访问等问题,这对于保证CUDA程序的稳定性和正确性非常有用。 **CUDA.c** 文件 `cuda.c`很可能是CUDA编程的一个示例或测试代码。它可能包含了CUDA的基本...

    Linux下的GDB调试手册

    这对于查找内存泄漏、越界访问等问题非常有用。 此外,GDB提供了丰富的命令用于分析调用栈,如`backtrace`(简写为`bt`)显示当前的调用堆栈,`up`和`down`则用于在调用栈上下移动。`frame`命令可以用来选择和切换...

    Linux下多线程编程.pdf

    为了保证缓冲区的数据完整性和系统的稳定运行,必须协调生产者和消费者线程的行为,确保不会发生缓冲区的越界访问和数据的竞争条件。为此,可以采用信号量来实现线程间的同步和互斥。 信号量是一种广泛使用的同步...

    linuxC内存极品文章《大内高手》

    3. **数组越界**:访问数组时超出其边界。 4. **双删**:同一个指针释放两次。 5. **悬挂指针**:指向即将被释放的内存。 #### 十、常用调试工具 1. **Valgrind**:用于检测内存泄漏和内存错误的强大工具。 2. **...

    Linux Debugging(五): coredump 分析入門1

    2. **内存越界**:当数组或动态内存区域被超出边界访问时,也会触发`SIGSEGV`。 3. **数据类型不匹配**:当指针转换错误,导致对非内存区域的访问,可能会产生这个信号。 4. **多线程并发问题**:如死锁、竞态条件或...

    bombbombbombbombbomb

    5. **内存分析**:使用`valgrind`检查潜在的内存泄漏、越界访问等问题。 6. **代码修改**:一旦找到触发条件,可能需要修改原始二进制文件,以避免“爆炸”。 在解决这类问题的过程中,理解操作系统原理,特别是...

    在不具备gdb环境的Linux系统上大致定位段错误位置

    - **越界访问**:数组或指针超出其合法范围,例如访问数组元素时索引超出了数组的实际大小。 - **空指针解引用**:尝试使用未初始化或值为`NULL`的指针。 - **特权问题**:尝试访问受操作系统保护的内存区域,这些...

    linux的一些命令解释

    ### Linux命令详解与应用场景 #### 一、PATH设置与环境变量管理 ...通过以上内容的学习和实践,可以帮助我们更好地理解和运用Linux系统中的一些基础命令和技术细节,提高日常工作效率和问题解决能力。

    嵌入式linux操作系统的设计.pdf

    嵌入式系统通过内存页面申请、释放和地址映射等功能,防止访问越界,提高程序运行的安全性。通过MMU(内存管理单元)的支持,可以更加便捷地管理和查询内存地址,减少资源浪费。 2. **Bootloader固件**:Bootloader...

    chp6 linux.rar

    在IT领域,尤其是在...在实际操作中,还需要注意数组边界,避免越界访问,以及合理地管理内存,防止内存泄漏。同时,对数组的深入理解和熟练运用也能为学习更复杂的C语言数据结构,如链表、树、图等打下坚实的基础。

    linux系统编程-静态库-动态库-gdb调试.zip

    遇到段错误(Segmentation Fault)时,GDB可以帮助定位问题所在,例如,可能是因为非法访问内存、空指针解引用或者数组越界等。 总结起来,这个资料包涵盖了Linux系统编程的核心概念:静态库和动态库的制作,以及...

    Linux C函数参考 内存控制篇.rar

    9. 常见内存错误:包括空指针解引用、内存泄漏、越界访问、双重释放等问题。理解和检测这些错误是保证程序健壮性的重要步骤。 10. 工具和技巧:使用`valgrind`等内存检查工具可以帮助定位内存问题。了解`glibc`内存...

    【正点原子】嵌入式Linux C代码规范化V1.0.zip

    嵌入式Linux开发中,C语言由于其高效、灵活和对硬件的直接访问能力,成为首选的编程语言之一。而良好的代码规范能帮助团队协作,减少错误,提升代码的可读性和可维护性。 嵌入式Linux C代码规范化主要包括以下几个...

    c语言学习,很好的总结资料。

    - **常见面试题深入剖析**:熟悉C/C++的基础知识,如变量声明、类型转换、运算符优先级、内存模型等,并掌握面试中常见的陷阱和误区,如数组越界、空指针引用等。 - **经典面试题实战演练**:通过解决具体的编程...

Global site tag (gtag.js) - Google Analytics