澳门新葡萄京官网首页 21

澳门新葡萄京官网首页linux缺页异常处理–内核空间【转】

旅馆式文件系统

Linux通过vfs虚构文件系统来归总抽象具体的磁盘文件系统,从上到下的IO栈形成了一个仓库式。通过对内核源码的分析,以叁次读操作为例,从上到下所实践的流水线如下:

澳门新葡萄京官网首页 1

基本中利用了累累c语言情势的面向对象,也正是函数指针的情势,比方read是vfs提供顾客的接口,具体底下调用的是ext2的read操作。大家只要完成VFS提供的种种接口,就足以兑现二个货仓式文件系统。Linux内核中朝气蓬勃度合併了部分酒馆式文件系统,比方Ubuntu在装置时会提醒您是或不是需求加密home目录,其实正是一个旅馆式的加密文件系统(eCryptfs),原理如下:

澳门新葡萄京官网首页 2

落到实处了一个仓库式文件系统,相当于具有的读写操作都会进入到大家的文件系统,可以得到独具的数据,就足以开展做一些拦住过滤。

以下是本身完毕的一个最简便易行的仓库式文件系统,实现了最轻易易行的展开、读写文件,麻雀虽小但麻雀虽小。

目录(?)[-]

1.主次设计的不当产生访谈了不法的地址

复苏原状

static void syscall_cleanup_module(void)
{
printk(KERN_ALERT "Module syscall unloaded.n");
make_rw((unsigned long)sys_call_table);
sys_call_table[__NR_getdents] = (unsigned long *)orig_getdents;
make_ro((unsigned long)sys_call_table);
}

应用Makefile编写翻译,insmod插入内核模块后,再实践ls时,就能进去到大家的连串调用,大家得以在hook代码中删掉有个别文件,ls就不会显示那么些文件,然则这几个文件大概存在的。

2 malloc 和free

malloc用于顾客空间堆扩张的函数接口。该函数是C库,归属封装了有关系统调用(brk(卡塔尔(قطر‎)的glibc库函数。实际不是系统调用(系统可不曾sys_malloc(卡塔尔国。如若谈及malloc函数涉及的种类基本的那个操作,那么总体能够分成顾客空间范围和水源空间层面来谈谈。

[cpp] view
plain copy

动态库威胁

Linux上的动态库劫持首倘若基于LD_
PRELOAD景况变量,那一个景况变量的第大器晚成效率是更换改态库的加载顺序,让客户有选拔的载入分歧动态库中的相符函数。不过使用不当就能够唤起严重的平安主题素材,大家可以通过它在主程序和动态连接库中加载别的动态函数,这就给大家提供了一个火候,向人家的次第注入恶意的代码。

若果有以下顾客名密码验证的函数:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char passwd[] = "password";
if (argc < 2) {
printf("Invalid argc!n");
return;
}
if (!strcmp(passwd, argv[1])) {
printf("Correct Password!n");
return;
}
printf("Invalid Password!n");
}

作者们再写意气风发段hookStrcmp的顺序,让那些相比永世精确。

#include <stdio.h>
int strcmp(const char *s1, const char *s2)
{
/* 永远返回0,表示两个字符串相等 */
return 0;
}

依次实行以下命令,就能够使大家的hook程序先推行。

gcc -Wall -fPIC -shared -o hookStrcmp.so hookStrcmp.c
export LD_PRELOAD=”./hookStrcmp.so

结果会意识,大家团结写的strcmp函数优先被调用了。那是三个最简便的胁迫,可是豆蔻年华旦遏抑了相近于geteuid/getuid/getgid,让其重返0,就相当于揭示了root权限。所认为了安全起见,日常将LD_
PRELOAD境况变量禁止使用掉。

  1. 1
    进度的顾客空间
  2.  12
    地址映射
  1. dotraplinkage void __kprobes  
  2. do_page_fault(struct pt_regs *regs, unsigned long error_code)  
  3. {  
  4.     struct vm_area_struct *vma;  
  5.     struct task_struct *tsk;  
  6.     unsigned long address;  
  7.     struct mm_struct *mm;  
  8.     int write;  
  9.     int fault;  
  10.   
  11.     tsk = current; //获取当前路程  
  12.     mm = tsk->mm;  //获取当前进程的地址空间  
  13.   
  14.     /* Get the faulting address: */  
  15.     address = read_cr2(卡塔尔(قطر‎; //读取C酷路泽2存放器获取触发格外的拜访地址  
  16.       
  17.     …  
  18.          …  
  19.   
  20.     if (unlikely(fault_in_kernel_space(addressState of Qatar卡塔尔国State of Qatar { //剖断address是还是不是处在内核线性地址空间  
  21.         if (!(error_code & (PF_RSVD | PF_USER | PF_PROT卡塔尔卡塔尔State of Qatar {//判定是或不是处在内核态  
  22.             if (vmalloc_fault(address) >= 0)//处理vmalloc异常  
  23.                 return;  
  24.   
  25.             if (kmemcheck_fault(regs, address, error_code))  
  26.                 return;  
  27.         }  
  28.   
  29.         /* Can handle a stale RO->RW TLB: */  
  30.         /*特别产生在基本地址空间但不归于地点的气象或地点的艺术不可能改进, 
  31.           则检查相应的页表项是还是不是存在,权限是不是丰富*/  
  32.         if (spurious_fault(error_code, address))  
  33.             return;  
  34.   
  35.         /* kprobes don’t want to hook the spurious faults: */  
  36.         if (notify_page_fault(regs))  
  37.             return;  
  38.         /* 
  39.          * Don’t take the mm semaphore here. If we fixup a prefetch 
  40.          * fault we could otherwise deadlock: 
  41.          */  
  42.         bad_area_nosemaphore(regs, error_code, address);  
  43.   
  44.         return;  
  45.     }  
  46.     …  
  47.     …  
  48. }  

LSM

LSM是Linux Secrity
Module的简单称谓,即linux安全模块。是大器晚成种通用的Linux安全框架,具有功效高,轻松易用等本性。原理如下:

澳门新葡萄京官网首页 3

LSM在基本中做了以下专业:

  1. 在特定的底蕴数据布局中步入安全域。
  2. 在内核源代码中不一致的关键点插入对平安钩子函数的调用。
  3. 加盟一个通用的平安体系调用。
  4. 提供了函数允许内核模块注册为平安模块只怕撤回。
  5. 将capabilities逻辑的许多移植为七个可选的铁岭模块,具有可扩充性。

ordeder原创,原作链接:

1.水源通过用户空间传递的类别调用参数,访谈了不算的地方

千帆竞发轮番系统调用

本文实现的是对 ls那几个命令对应的体系调用,系统调用号是 _ NR _getdents。

static int syscall_init_module(void)
{
orig_getdents = sys_call_table[__NR_getdents];
make_rw((unsigned long)sys_call_table); //修改页属性
sys_call_table[__NR_getdents] = (unsigned long *)hacked_getdents; //设置新的系统调用地址
make_ro((unsigned long)sys_call_table);
return 0;
}

1.1 进度的客户空间

澳门新葡萄京官网首页 4

 

 

图1:来源

 

该协会是由进度task_struct.mm_struct举办拘留的mm_struct的定义如下:

 

[cpp] view
plain copy

 

 澳门新葡萄京官网首页 5澳门新葡萄京官网首页 6

  1. struct mm_struct {  
  2.     struct vm_area_struct * mmap;   /* list of VMAs */  
  3.     …  
  4.     pgd_t * pgd;                //用于地址映射  
  5.     atomic_t mm_users;          /* How many users with user space? */  
  6.     atomic_t mm_count;          /* How many references to “struct mm_struct” (users count as 1) */  
  7.     int map_count;              /* number of VMAs */  
  8.     …  
  9.     //描述顾客空间的段布满:数据段,代码段,仓库段  
  10.     unsigned long start_code, end_code, start_data, end_data;  
  11.     unsigned long start_brk, brk, start_stack;  
  12.     unsigned long arg_start, arg_end, env_start, env_end;  
  13.     unsigned long rss, total_vm, locked_vm;  
  14.     …  
  15. };  

 

构造中的startxxx与endxxx描述了经过客商空间数据段的八方地点。对于堆空间来讲,start_brk是堆空间的伊始地址,堆是演变扩充的。对于经过堆空间的强盛,brk来记录堆的顶端地点。而经过动态申请的空中的已经使用到之处空间(正在使用的变量)是被映射的,这一个地址空间记录于链表struct
vm_area_struct * mmap中。

[cpp] view
plain copy

Linux系统调用勒迫

近来意识在4.4.0的内核中有513三个系统调用(相当多都没用过卡塔尔国,系统调用抑遏的目标是退换系统中原来的系统调用,用大家友好的顺序替换原有的体系调用。Linux内核中有着的系统调用都以身处叁个堪当sys_
call
_table的根本数组中,数组的值就象征这一个类别调用服务程序的输入地址。整个系统调用的流水生产线如下:

澳门新葡萄京官网首页 7

当顾客态发起二个系统调用时,会透过80软中断步入到syscall
hander,进而进入全局的种类调用表sys_ call
_table去搜寻具体的系统调用,那么生机勃勃旦大家将以此数组中的地址改成大家相濡以沫的前后相继地址,就能够完结系统调用威逼。然则底蕴为了安全,对这种操作做了一些节制:

  1. sys_ call _table的号子未有导出,不能够直接获得。
  2. sys_ call _table所在的内部存款和储蓄器页是只读属性的,不能够间接进行修正。

对此上述多个难题,解决方案如下(方法不只有黄金年代种):

  1. 获取sys call table的地址 :grep sys _ call _table
    /boot/System.map-uname -r
  2. 垄断页表只读属性是由CQashqai0存放器的WP位调节的,只要将这几个位清零就足以对只读页表实行改造。

    / make the page writable /
    int make_rw(unsigned long address)
    {
    unsigned int level;
    pte_t *pte = lookup_address(address, &levelState of Qatar;//查找虚构地址所在的页表地址
    pte->pte |= _PAGE_卡宴W;//设置页表读写属性
    return 0;
    }

    / make the page write protected /
    int make_ro(unsigned long address)
    {
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    pte->pte &= ~_PAGE_奥德赛W;//设置只读属性
    return 0;
    }

转自:

 

inline hook

咱俩领会根本中的函数不容许把装有效用都在这里个函数中全体达成,它必定会就要调用它的下层函数。假若这么些下层函数可以获得大家想要的过滤音讯内容,就足以把下层函数在上层函数中的offset替换到新的函数的offset,那样上层函数调用下层函数时,就能跳到新的函数中,在新的函数中做过滤和绑架内容的办事。所以从常理上来讲,inline
hook能够想hook何地就hook何地。

澳门新葡萄京官网首页 8

正文介绍malloc的兑现及其malloc在进行堆扩大操作,并解析了虚构地址到大意地址是什么样兑现映射关系。

 

Linux中普及的拦截过滤

本文重视介绍Linux平台上广泛的遏止:

  1. 客商态动态库拦截。
  2. 内核态系统调用拦截。
  3. 货仓式文件系统拦截。
  4. inline hook拦截。
  5. LSM(Linux Security Modules)

参考

[cpp] view
plain copy

适用项景

对此上述两种Hook方式,有其分化的使用处景。

  1. 动态库威迫不太完全,威逼的信息有异常的大希望满意不断大家的须要,还应该有极大可能率别人在您前面逼迫了,后生可畏旦禁止使用LD_
    PRELOAD就失效了。
  2. 系统调用强迫,威胁的音讯有十分大或者满意不断大家的须要,比如不可能博取struct
    file构造体,不能够博取文件的相对路线等。
  3. 饭馆式文件系统,正视于Mount,可能须求重启系统。
  4. inline
    hook,灵活性高,随便Hook,即时生效无需重启,不过在不一致功底版本之间通用性差,意气风发旦某个函数发生了转移,Hook失效。
  5. LSM,在中期的木本中,只可以同意叁个LSM内核模块加载,举个例子加载了SELinux,就不可能加载其余的LSM模块,在最新的内核版本中不设有这些主题素材。

2.2 内核层

 

上文中,malloc的空闲chunk列表不只怕满意顾客的须求,那么要通过sys_brk(卡塔尔国举行堆的强盛,这个时候才真正算得上跻身底蕴空间。
sys_brk(State of Qatar涉及的最首要操作有:

  1. 在mm_struct中的堆上界brk延伸到newbrk:即申请一块vma,vma.start=brk
    vma.end=newbrk
    2.
    为该设想区间块实行物理内存的照射:从虚构空间vma.start~vma.end中的每种内部存储器页进行映射:

[cpp] view
plain copy

 

 澳门新葡萄京官网首页 9澳门新葡萄京官网首页 10

  1. addr = vma.start  
  2. do{  
  3.   handle_mm_fault(mm,vma,addr,…)  
  4.   addr += PAGESIZE  
  5. }while(addr< vma.end)  

 

函数handle_mm_fault为addr所在的内部存款和储蓄器页映射物理页面。完毕虚构空间到大要空间的折算和照耀。

1.通过alloc_page申请三个物理页面;

2.换算addr在经过pdg映射中所在的pte地址;

3.将addr对应的pte设置为概况页面包车型客车首地址。

澳门新葡萄京官网首页 11

版权讲明:本文为博主原创作品,未经博主允许不得转发。

背景

近年来,我们的类型组在帮客户解决部分操作系统安全领域的标题,涉及到windows,Linux,macOS三大操作系统平台。无论什么样操作系统,本质上都以三个软件,任何软件在后生可畏初叶筹算的时候,都无法一切的满意大家的供给,所以操作系统也是同生龙活虎,为了尽大概的满足大家须求,不能不提供部分供大家定制操作系统的体制。当然除了官方提供的后生可畏都部队分建制,也许有大器晚成对黑法力,这么些黑法力不被推荐使用,不过临时面临现实的政工场景,能够视作三个参照他事他说加以考察的笔触。

3 总结

 

1 Malloc 和 free 怎么望着就是个客户空间的内部存款和储蓄器池。特别free的贯彻。

2 堆的增加依赖brk的运动。Vm_area记录了设想空间中已选用之处块。

3
每个进度的设想地址到轮廓地址的投射是有经过mm.pgd决定的,在该组织中记录了虚构页号到大意页号的映照关系。

[cpp] view
plain copy

对此第二个难题:

须要有少数的基本源码资历,比方说对于read操作,源码如下:

澳门新葡萄京官网首页 12

在这里处当发起read系统调用后,就能进来到sys read,在sys read中会调用vfs read函数,在vfs read的参数中正巧有大家要求过滤的新闻,那么就能够把vfs_
read当作叁个hook点。

 

  1. static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)  
  2. {  
  3.     unsigned index = pgd_index(address);  
  4.     pgd_t *pgd_k;  
  5.     pud_t *pud, *pud_k;  
  6.     pmd_澳门新葡萄京官网首页 ,t *pmd, *pmd_k;  
  7.   
  8.     pgd += index; //记录当前页表pgd对应address的撼动  
  9.     pgd_k = init_mm.pgd + index;//记录内核页表对应address的舞狮  
  10.   
  11.     if (!pgd_present(*pgd_k卡塔尔国卡塔尔国//内核PGD页表对应的项不设有,则不或者开展下一步,再次回到NULL  
  12.         return NULL;  
  13.   
  14.     /* 
  15.      * set_pgd(pgd, *pgd_k); here would be useless on PAE 
  16.      * and redundant with the set_pmd() on non-PAE. As would 
  17.      * set_pud. 
  18.      */  
  19.        
  20.     /*赢伏贴前页表对应address的PUD地址和功底页表对应address的地址,并认清pud_k对应的项是或不是留存*/  
  21.     pud = pud_offset(pgd, address);  
  22.     pud_k = pud_offset(pgd_k, address);  
  23.     if (!pud_present(*pud_k))  
  24.         return NULL;  
  25.   
  26.     /*对pmd进行和方面相近的操作*/  
  27.     pmd = pmd_offset(pud, address);  
  28.     pmd_k = pmd_offset(pud_k, address);  
  29.     if (!pmd_present(*pmd_k))  
  30.         return NULL;  
  31.   
  32.     if (!pmd_present(*pmd卡塔尔(قطر‎State of Qatar//当前选择页表对应的pmd项不设有,则改进pmd项使其和根本页表的pmd_k项相同  
  33.         set_pmd(pmd, *pmd_k);  
  34.     else  
  35.         BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));  
  36.   
  37.     return pmd_k;  
  38. }  

总结

篇幅有限,本文只是介绍了Linux上的拦截手艺,后续有空子能够生机勃勃并研讨windows和macOS上的阻碍技艺。事实上相近的审计HOOK放到任何一个种类中都以刚需,不只是kernel,大家能够观看越来越多的vm和runtime以至席卷过多web组件、前端接受都提供了越来越灵活的hook格局,那是透明化和实时性两个安全大趋势下最广大的技术方案。

1背景知识

        缺页相当被触发日常有三种情形——

对此第四个难点:

何以Hook?这里介绍三种艺术:

首先种办法:间接开展二进制替换,将call指令的操作数替换为hook函数之处。

澳门新葡萄京官网首页 13

第两种办法:Linux内核提供的kprobes机制。

其规律是在hook点注入int
3(x86卡塔尔的机器码,让cpu运转到那边的时候会触发sig trap实信号,然后将客商自定义的hook函数注入到sig trap的回调函数中,达到触发hook函数的指标。这些其实也是调节和测验器的法规。

2.3 设想地址与物理地址

 

当进程读取堆空间的地址vaddr时,设想地址vaddr到概略页面包车型大巴炫目如下图所示。

澳门新葡萄京官网首页 14

 

1.
客户空间的设想地址vaddr通过MMU(pgd,pmd,pte)找到相应的页表项pte记录的物理地址paddr

  1. 页表项paddr的高十七个人是物理页号:index = x >>
    PAGE_SHIFT,同理,index前边补上12个0正是大意页表的首地址。
    3.
    经过物理页号,大家能够再基本中找到该物理页的描述的指针mem_map[index]。Page布局得以参照他事他说加以侦察。

 

该函数字传送递步入的多少个参数–

inline hook 有多少个首要的难题:

  1. 怎么定位hook点。
  2. 什么注入hook函数入口。

版权申明:本文为博主(

  1. /* 
  2.  * Page fault error code bits: 
  3.  * 
  4.  *   bit 0 ==    0: no page found   1: protection fault 
  5.  *   bit 1 ==    0: read access     1: write access 
  6.  *   bit 2 ==    0: kernel-mode access  1: user-mode access 
  7.  *   bit 3 ==               1: use of reserved bit detected 
  8.  *   bit 4 ==               1: fault was an instruction fetch 
  9.  */  
  10. enum x86_pf_error_code {  
  11.   
  12.     PF_PROT     =       1 << 0,  
  13.     PF_WRITE    =       1 << 1,  
  14.     PF_USER     =       1 << 2,  
  15.     PF_RSVD     =       1 << 3,  
  16.     PF_INSTR    =       1 << 4,  
  17. };  

1背景知识

[cpp] view
plain copy

malloc
和free

      
缺页至极的处理函数为do_page_fault(卡塔尔,该函数是和系统构造有关的叁个函数,缺页相当的来源于可分为二种,生龙活虎种是水源空间(访问了线性地址空间的第四个GB卡塔尔,风华正茂种是客商空间(访问了线性地址空间的0~3GB卡塔尔国,以X86布局为例,先来看底工空间十三分的拍卖。

附录

  1. static noinline int vmalloc_fault(unsigned long address)  
  2. {  
  3.     unsigned long pgd_paddr;  
  4.     pmd_t *pmd_k;  
  5.     pte_t *pte_k;  
  6.   
  7.     /* 分明触发非凡的地址是不是处在VMALLOC区域*/  
  8.     if (!(address >= VMALLOC_START && address < VMALLOC_END))  
  9.         return -1;  
  10.   
  11.     /* 
  12.      * Synchronize this task’s top level page-table 
  13.      * with the ‘reference’ page table. 
  14.      * 
  15.      * Do _not_ use “current” here. We might be inside 
  16.      * an interrupt in the middle of a task switch.. 
  17.      */  
  18.     pgd_paddr = read_cr3(卡塔尔;//获取当前的PGD地址  
  19.     pmd_k = vmalloc_sync_one(__va(pgd_paddr卡塔尔(قطر‎, address卡塔尔;//将眼下接纳的页表和根本页表同步  
  20.     if (!pmd_k)  
  21.         return -1;  
  22.   
  23.     /*到此处生机勃勃度收获了根底页表对应于address的pmd,并且将该值设置给了方今采纳页表的pmd, 
  24.       最终一步正是判别pmd对应的pte项是或不是留存*/  
  25.     pte_k = pte_offset_kernel(pmd_k, address);//获取pmd对应address的pte项  
  26.     if (!pte_present(*pte_k卡塔尔国State of Qatar//决断pte项是或不是留存,子虚乌有则退步  
  27.         return -1;  
  28.   
  29.     return 0;  
  30. }  

附录

 

[cpp] view
plain copy

 

 澳门新葡萄京官网首页 15澳门新葡萄京官网首页 16

  1. #define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))  
  2. int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,  
  3.     unsigned long address, int write_access)  
  4. {  
  5.     int ret = -1;  
  6.     pgd_t *pgd;  
  7.     pmd_t *pmd;  
  8.   
  9.     pgd = pgd_offset(mm, address);  
  10.     pmd = pmd_alloc(pgd, address);  
  11.   
  12.     if (pmd) {  
  13.         pte_t * pte = pte_alloc(pmd, address卡塔尔国; //pmd是空的,所以回来的是pgd[address]的pte项目  
  14.         if (pte)  
  15.             ret = handle_pte_fault(mm, vma, address, write_access, pte);  
  16.     }  
  17.     return ret;  
  18. }  
  19.   
  20. //叁十几人地点,pmd聊无意义  
  21. extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)  
  22. {  
  23.     return (pmd_t *) pgd;  
  24. }  
  25.   
  26. //为address地址所在的页创设pte索引项  
  27. extern inline pte_t *pte_alloc(pmd_t *pmd, unsigned long address)  
  28. {  
  29.     address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE – 1);  
  30.     if (pmd_none(*pmd)) {  
  31.         pte_t *page = get_pte_fast();  
  32.   
  33.         if (!page)  
  34.             return get_pte_slow(pmd, address);  
  35.         pmd_set(pmd,page);  
  36.         return page + address;  
  37.     }  
  38.     if (pmd_bad(*pmd)) {  
  39.         __bad_pte(pmd);  
  40.         return NULL;  
  41.     }  
  42.     return (pte_t *)__pmd_page(*pmd) + address;  
  43. }  
  44.   
  45. //为address对应的页面分配物理页面  
  46. static inline int handle_pte_fault(struct mm_struct *mm,  
  47.     struct vm_area_struct * vma, unsigned long address,  
  48.     int write_access, pte_t * pte)  
  49. {  
  50.     pte_t entry;  
  51.     entry = *pte;  
  52.     if (!pte_present(entry)) {  
  53.         …  
  54.         if (pte_none(entry))  
  55.             return do_no_page(mm, vma, address, write_access, pte卡塔尔(قطر‎;//缺页,分配物理页  
  56.         …  
  57.     }  
  58.     …  
  59.     return 1;  
  60. }  
  61.   
  62.   
  63. static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,  
  64.     unsigned long address, int write_access, pte_t *page_table)  
  65. {  
  66.     struct page * new_page;  
  67.     pte_t entry;  
  68.     //无名(对于虚构存款和储蓄空间来说)的情理映射  
  69.     if (!vma->vm_ops || !vma->vm_ops->nopage)  
  70.         return do_anonymous_page(mm, vma, page_table, write_access, address);  
  71.   
  72.   //一下是文本的缺页管理,在这里不表  
  73.     …  
  74. }  
  75.   
  76. //通过page指针,就能够测算page的物理地址: 物理地址 = (page指针 – mem_map)* 页大小 + 物理内部存款和储蓄器起首地址  
  77. /* 
  78.  * 佚名映射,用于虚存到大要内部存储器 
  79.  */  
  80. static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)  
  81. {  
  82.     struct page *page = NULL;  
  83.     pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));  
  84.     if (write_access) {  
  85.         page = alloc_page(GFP_HIGHUSE奥迪Q5卡塔尔; //从高等内部存款和储蓄器中分配内部存款和储蓄器  
  86.         if (!page)  
  87.             return -1;  
  88.         clear_user_highpage(page, addr);  
  89.         entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));  
  90.         mm->rss++;  
  91.         flush_page_to_ram(page);  
  92.     }  
  93.     set_pte(page_table, entry); // *page_table = entry;  
  94.     /* No need to invalidate – it was non-present before */  
  95.     update_mmu_cache(vma, addr, entry);  
  96.     return 1;   /* Minor fault */  
  97. }  
  98.   
  99. #define __MEMORY_START      CONFIG_MEMORY_START //物理内部存款和储蓄器中用于动态分配使用的开首地址  
  100. void flush_page_to_ram(struct page *pg)  
  101. {  
  102.     unsigned long phys;  
  103.   
  104.     /* Physical address of this page */  
  105.     phys = (pg – mem_map)*PAGE_SIZE + __MEMORY_START;  
  106.     __flush_page_to_ram(phys_to_virt(phys));  
  107. }  
  108.   
  109. #define __virt_to_phys(vpage) ((vpage) – PAGE_OFFSET + PHYS_OFFSET)  
  110. #define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET – PHYS_OFFSET)  

澳门新葡萄京官网首页 17

2.幼功的顺序设计缺欠

总结

首先种情况根本尚且能经过丰盛改良机制来开展修补,而第二种状态就能促成OOPS错误了,内核将抑遏用SIGKILL甘休近日进度。

参考

底子源码情景剖判

内核态的bad_area_nosemaphore(卡塔尔国的骨子里管理函数为bad_area_nosemaphore()–>__bad_area_nosemaphore()–>no_context()

 

error_code是触发万分的不当类型,它的含义如下

 1.2 地址映射

设想地址和轮廓地址的映射 :

 

上边解释一下第二种状态,那是设想内存管理的一个特色。就算各类进程独立具备3GB的可访谈地址空间,然而这几个财富都以根本开出的空话,也正是说进度手握着和友爱唇齿相依的三个个虚构内部存储器区域(vma卡塔尔,不过这个虚构内部存款和储蓄器区域并不会在创建的时候就和轮廓页框挂钩,由于程序的区域性原理,程序在一如时期内所访谈的内部存款和储蓄器往往是少数的,由此基本只会在经过确确实实供给寻访物理内部存款和储蓄器时才会将相应的设想内部存储器区域与物理内部存款和储蓄器进行关联(为对应的地址分配页表项,并将页表项映射到大要内部存款和储蓄器卡塔尔国,也正是说这种缺页卓殊是不荒谬的,而首先种缺页分外是不健康的,内核要动用各类一蹴而就的手腕将这种非常带给的磨损失减少到微小。

  1. 1 用户层
  2. 2 内核层
  3. 3
    虚构地址与物理地址
  1. <span style=”font-size:12px;”>static noinline void  
  2. no_context(struct pt_regs *regs, unsigned long error_code,  
  3.        unsigned long address)  
  4. {  
  5.     struct task_struct *tsk = current;  
  6.     unsigned long *stackend;  
  7.     unsigned long flags;  
  8.     int sig;  
  9.   
  10.     /* Are we prepared to handle this kernel fault? */  
  11.     /*fixup_exception()用于搜索分外表,并思忖找到一个对应当十一分的例程来张开修改, 
  12.       那一个例程在fixup_exception(卡塔尔(قطر‎重返后进行*/  
  13.     if (fixup_exception(regs))  
  14.         return;  
  15.   
  16.     /* 
  17.      * 32-bit: 
  18.      * 
  19.      *   Valid to do another page fault here, because if this fault 
  20.      *   had been triggered by is_prefetch fixup_exception would have 
  21.      *   handled it. 
  22.      * 
  23.      * 64-bit: 
  24.      * 
  25.      *   Hall of shame of CPU/BIOS bugs. 
  26.      */  
  27.     if (is_prefetch(regs, error_code, address))  
  28.         return;  
  29.   
  30.     if (is_errata93(regs, address))  
  31.         return;  
  32.   
  33.     /* 
  34.      * Oops. The kernel tried to access some bad page. We’ll have to 
  35.      * terminate things with extreme prejudice: 
  36.      */  
  37.     /* 走到这里就证实非常确实是由于底工的次第设计缺欠变成的了,内核将 
  38.        发生一个oops,上面包车型客车干活就是打字与印刷CPU寄放器和内核态货仓的音讯到调节台并 
  39.        终结当前的进度*/  
  40.     flags = oops_begin();  
  41.   
  42.     show_fault_oops(regs, error_code, address);  
  43.   
  44.     stackend = end_of_stack(tsk);  
  45.     if (*stackend != STACK_END_MAGIC)  
  46.         printk(KERN_ALERT “Thread overran stack, or stack corruptedn”);  
  47.   
  48.     tsk->thread.cr2      = address;  
  49.     tsk->thread.trap_no  = 14;  
  50.     tsk->thread.error_code   = error_code;  
  51.   
  52.     sig = SIGKILL;  
  53.     if (__die(“Oops”, regs, error_code))  
  54.         sig = 0;  
  55.   
  56.     /* Executive summary in case the body of the oops scrolled away */  
  57.     printk(KERN_EMERG “CR2: %016lxn”, address);  
  58.   
  59.     oops_end(flags, regs, sig);  
  60. }  
  61. </span>  

2.1 用户层

 

malloc 的源码可以看到

Malloc和free是在客商层职业的,该接口为客户提供三个比较便利管理堆的接口。它的最首要职业是体贴叁个空余的堆空间缓冲区链表。该缓冲区能够用如下数据构造表述:

 

[cpp] view
plain copy

 

 澳门新葡萄京官网首页 18澳门新葡萄京官网首页 19

  1. struct malloc_chunk {  
  2.     INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */  
  3.     INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */  
  4.     struct malloc_chunk* fd; /* double links — used only if free. */  
  5.     struct malloc_chunk* bk;  
  6.     /* Only used for large blocks: pointer to next larger size. */  
  7.     struct malloc_chunk* fd_nextsize; /* double links — used only if free. */  
  8.     struct malloc_chunk* bk_nextsize;  
  9. };  

 

简化版的闲暇缓冲区链表如下所示,图中head即为上述的malloc_chunk布局。而随着的size大小的内部存款和储蓄器区间是该chunk对应的数据区。

澳门新葡萄京官网首页 20

【malloc】

       
每当进度调用malloc,首先会在该堆缓冲区寻觅丰裕大小的内部存款和储蓄器块分配给过程(选取缓冲区中的那多少个块就有第三回打夹钟最棒命中三种算法)。如若freechunklist已回天乏术满足须求的chunk时,那么malloc会通过调用系统调用brk(卡塔尔国将经过空间的堆实行增加,在新扩展的堆空间上树立叁个新的chunk并步向到freelist中,这么些进程也正是经过批量想系统报名一块内部存款和储蓄器(大小可能比其实供给大得多)。

       malloc再次来到的地址是chunk的中用于存款和储蓄数据的首地址,即: chunk +
sizeof(chunk)

澳门新葡萄京官网首页 21

二个简单易行的第叁遍命中malloc的伪代码:

[cpp] view
plain copy

 

 澳门新葡萄京官网首页 22澳门新葡萄京官网首页 23

  1. chunk free_list  
  2. malloc(size)  
  3.   foreach(chuck in freelist)  
  4.     if(chunk.size >size)  
  5.       return chunk + sizeof(chunk)  
  6.   //空闲缓冲区不可能满意急需,那么像系统批发内部存款和储蓄器  
  7.   add = sys_brk(brk+(size +sizeof(chunk)))  
  8.   newchunk = (chunk)add;  
  9.   newchunk.size = size;  
  10.   …  
  11.   return newchunk + sizeof(newchunk)  

 

【free】

       
free操作是对堆空间的回笼,回收的区块并非这时返还给幼功。而是将区块对应的chunk“标志”为空闲,参加空闲队列中。当然,要是空闲队列中现身相邻地址的chunk,那么能够杜撰合併,已解决内部存款和储蓄器的碎片化,一次满足以往的大内存申请的供给。

五个精练的free伪代码:将释放之处空间插手空闲链表中

 

[cpp] view
plain copy

 

 澳门新葡萄京官网首页 24澳门新葡萄京官网首页 25

  1. free(add)  
  2.   pchunk = add – sizeof(chunk)  
  3.   insert_to_freelist(pchunk)  

二只管理:

率先要反省该极度的接触地址是或不是身处内核地址空间
也正是address>=TASK_SIZE_MAX,平日为3GB。然后要反省触发卓殊时是不是处在内核态,知足那多个规范就尝试通过vmalloc_fault(卡塔尔国来缓慢解决那些极其。由于接纳vmalloc申请内部存款和储蓄器时,内核只会更新主内核页表,所以当前利用的经过页表就有相当的大大概因为未与主内核页表同步引致此番分外的接触,由此该函数总计将address对应的页表项与主内核页表进行联合

 如果do_page_fault(卡塔尔函数实践到了bad_area_nosemaphore(卡塔尔,那么就表明本次特别是由于对违规之处访谈形成的。在基本中生出这么的结果的状态相像有两种:

regs蕴涵了逐个寄放器的值

 

转自:

 

2.拜谒的地点是官方的,不过该地点还未有分配物理页框

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注