Protection 6 ---- Page-Level Protection

原创 2013年12月05日 14:39:35

页级别的保护类型

对于分页结构的保护分为两种,一种是对于访问权限的检查,一种是对于线性地址是否存在转换进行检查。

访问权限

分页结构中的一些位是用来规定页的访问权限的,例如R/W,U/S以及XD。这些位在不同的访问模式下起着不同的限制作用。对于一个线性地址的访问有两种模式:supervisor-mode以及user-mode。当CPL<3的时候是supervisor-mode,CPL==3是user-mode。下面这些规则是Intel手册中列举出来的不同的访问权限:

  • supervisor-mode
    • 读数据
      • 可以从任何线性地址读取数据
    • 写数据
      • CR0.WP==0,可以向任何线性地址写数据
      • CR0.WP==1,只能向地址转换过程中使用的分页结构中R/W==1的线性地址写数据
    • 执行
      • 32-Bit Paging或者IA32_EFER.NXE==0,访问权限依赖于CR4.SEMP
        • CR4.SEMP==0,可以执行任何线性地址中的指令
        • CR4.SEMP==1,只能执行转换过程中使用的分页结构的U/S==0的线性地址中的指令
      • PAE Paging或者IA-32e Paging并且IA32_EFER.NXE==1,访问权限也依赖于CR4.SEMP
        • CR4.SEMP==0,只能执行转换过程中使用的分页结构的XD==0的线性地址中的指令
        • CR4.SEMP==0,只能执行转换过程中使用的分页结构的U/S==0并且XD==0的现行地址中的指令
  • user-mode
    • 读数据
      • 只能读取转换过程中使用的分页结构的U/S==1的线性地址中的数据
    • 写数据
      • 只能向转换过程中使用的分页结构的U/S==1并且R/W==1的线性地址中写数据
    • 执行
      • 32-Bit Paging或者IA32_EFER.NXE==0,可以执行地址转换过程中使用的分页结构的U/S==1的线性地址中的指令
      • PAE Paging或者IA-32e Paging并且IA32_EFER.NXE==1,可以执行地址转换过程中分页结构的U/S==1并且XD==0的线性地址中的指令

没有地址转换

另一种检查是检查线性地址在现有的分页结构中有没有转换,所谓没有转换就是线性地址在转换过程中使用的分页结构的P==0或者是保留位被设置。


#PF异常

如果对于一个线性地址的转换过程中违反了上述两种检查,那么就会触发#PF异常。下图是#PF的error code,它描述了#PF的类型:


  • P:
    • 0:异常是由于不存在的页引起的
    • 1:异常是由于违反了Page-Level保护引起的
  • W/R:
    • 0:异常是由于读访问引起的
    • 1:异常是由于写访问一起的
  • U/S:
    • 0:异常是由于supervisor-mode引起的
    • 1:异常是由于user-mode引起的
  • RSVD:
    • 0:异常不是由于保留位被设置引起的
    • 1:异常是由于某些分页结构的保留位被设置引起的
  • I/D:
    • 0:异常不是由于取指引起的
    • 1:异常是由于取指引起的


例子

这里的例子主要是模拟由于没有地址转换导致#PF异常,并且在#PF异常处理程序中修改错误的情况。

首先要准备一段可执行的代码,这段代码要拷贝到能够引起#PF异常的线性地址中以便测试使用。

code_start:
    movl $puts, %ebx
    movl $dump_pae_page, %edx

    movl $msg3, %esi
    call *%ebx
    movl $println, %eax
    call *%eax
    movl $0x400000, %esi
    call *%edx
    movl $println, %eax
    call *%eax

    jmp .
code_end:
这段代码也是通过dump_pae_page来打印一个线性地址的转换过程。

接下来要将这段代码拷贝到测试的地址中,我们使用了0x400000地址为测试地址,不过拷贝的过程要在开启分页之前进行,否则拷贝的过程就会导致#PF。

    /*
     * copy code to 0x400000
     */
    movl $code_start, %esi
    movl $0x400000, %edi
    movl $code_end, %ecx
    subl %esi, %ecx
    rep movsb
测试代码准备好了,调用init_pae32_paging来初始化PAE Paging结构,这个结构和《PAE Paging》中的分页结构相同,不过就是在0x400000地址转换过程中PDE的保留位被设置了,PTE的P标志被清0,这两种情况都会导致#PF。
###############################################################
# init_pae32_paging:
init_pae32_paging:
    movl $PDPT_BASE, %esi
    call clear_4k_page
    movl $0x201000, %esi
    call clear_4k_page
    movl $0x202000, %esi
    call clear_4k_page

    # PDPTE[0]
    movl $PDPT_BASE, %esi
    movl $0x201001, (%esi)
    movl $0x00, 4(%esi)
    # PDE[0] 0x00 ~ 0x1fffff (2M)
    # PDE[1] 0x200000 ~ 0x3fffff (2M)
    # PDE[2] 0x400000 ~ 0x400fff (4K)
    movl $0x201000, %esi
    movl $0x00, %eax
    movl $0x00000087, (%esi, %eax, 8)
    movl $0x00, 4(%esi, %eax, 8)
    inc %eax
    movl $0x00200087, (%esi, %eax, 8)
    movl $0x00, 4(%esi, %eax, 8)
    inc %eax
    movl $0x00202007, (%esi, %eax, 8)
    movl $0x70000000, 4(%esi, %eax, 8)
    # PTE[0] 0x400000 ~ 0x400fff (4K)
    movl $0x202000, %esi
    movl $0x00400000, (%esi)
    /*
    movl xd_bit, %eax
    movl %eax, 4(%esi)
    */
    ret
然后就是编写#PF处理代码了,这里能够修改线性地址转换过程中由于数据结构中保留位被设置以及P标志为0的异常。
###############################################################
# PF_handler():
PF_handler:
    jmp do_PF_handler
pf_msg1:  .asciz  "----> Now, enter #PF handler, occur at: 0x"
pf_msg2:  .asciz  "----> Error Code: 0x"
pf_msg3:  .asciz  "----> fixup <----"
do_PF_handler:
    popl %esi
    pushl %ecx
    pushl %edx
    pushl %ebx

    movl %esi, %ebx
    # puts error address
    movl $pf_msg1, %esi
    call puts
    movl %cr2, %ecx
    movl %ecx, %esi
    call print_int_value
    call println
    # puts error code
    movl $pf_msg2, %esi
    call puts
    movl %ebx, %esi
    call print_int_value
    call println

    call get_maxphyadd
    pushl %ecx
    leal -64(%eax), %ecx
    negl %ecx
    movl $-1, %edi
    shll %cl, %edi
    shrl %cl, %edi
    popl %ecx

# fix error
get_pdpte:
    movl %ecx, %eax
    shrl $30, %eax
    andl $0x03, %eax
    movl $PDPT_BASE, %ebx

    # PDPTE
    pushl %edi
    movl 4(%ebx, %eax, 8), %edx
    notl %edi
    andl %edx, %edi
    jz get_pdpte_low
    popl %edi
    andl %edi, %edx
    movl %edx, 4(%ebx, %eax, 8)
    jmp do_PF_handler_done

get_pdpte_low:
    popl %edi
    movl (%ebx, %eax, 8), %edx
    btsl $0, %edx
    movl %edx, (%ebx, %eax, 8)
    jnc do_PF_handler_done

get_pde:
    #PDE
    movl %edx, %ebx
    andl $0xfffff000, %ebx
    movl %ecx, %eax
    shrl $21, %eax
    andl $0x01ff, %eax

    pushl %edi
    movl 4(%ebx, %eax, 8), %edx
    notl %edi
    andl $0x7fffffff, %edi
    andl %edx, %edi
    jz get_pde_low
    popl %edi
    orl $0x80000000, %edi
    andl %edi, %edx
    movl %edx, 4(%ebx, %eax, 8)
    jmp do_PF_handler_done

get_pde_low:
    popl %edi
    movl (%ebx, %eax, 8), %edx
    btsl $0, %edx
    movl %edx, (%ebx, %eax, 8)
    jnc do_PF_handler_done
    bt $7, %edx
    movl %edx, (%ebx, %eax, 8)
    jc do_PF_handler_done

get_pte:
    #PTE
    movl %edx, %ebx
    andl $0xfffff000, %ebx
    movl %ecx, %eax
    shrl $12, %eax
    andl $0x01ff, %eax

    pushl %edi
    movl 4(%ebx, %eax, 8), %edx
    notl %edi
    andl $0x7fffffff, %edi
    andl %edx, %edi
    jz get_pte_low
    popl %edi
    orl $0x80000000, %edi
    andl %edi, %edx
    movl %edx, 4(%ebx, %eax, 8)
    jmp do_PF_handler_done

get_pte_low:
    popl %edi
    movl (%ebx, %eax, 8), %edx
    btsl $0, %edx
    movl %edx, (%ebx, %eax, 8)
    jc do_PF_handler_done

do_PF_handler_done:

    movl $pf_msg3, %esi
    call puts
    call println
    call println

    popl %ebx
    popl %edx
    popl %ecx
    iret

最后在开启分页之后,首先对线性地址0x400000的转换过程进行打印,然后逃转到0x400000地址去执行其中的指令,由于0x400000地址中的指令也是打印对于线性地址0x400000的转换过程,所以执行结构应该看到两次对于0x400000线性地址的转换过程的打印结构。

    movl $msg3, %esi
    call puts
    call println
    movl $0x400000, %esi
    call dump_pae_page
    call println

    ljmp $KERNEL_CODE32_SELECTOR, $0x400000

最后的执行结构:


从执行结果可以看出,从第一次打印的结构来看,对线性地址0x400000的转换中使用的PDE的保留位被设置了,PTE的P标志被清0,所以没有对线性地址0x400000的转换。接下来的两次#PF正是由于跳转到0x400000地址去执行指令导致的。

第一次#PF是由PDE的保留位被设置导致的,从错误代码中可以看到,0x19表示P==1,RSVD==1,I/D==1,这说明异常是由于违反了页级别的保护引起的,具体是由于一些分页结构的保留位被设置引起的,同时是在取指令时引起的。接下来#PF处理过程修复了这个错误。

第一次#PF异常处理结束后,会重现执行跳转代码,但是这是线性地址0x400000仍然没有转换,所以导致了第二次#PF异常。

第二次#PF是由PTE的P标记被清0导致的,从错误代码中可以看出,0x10表示P==0,I/D==1,这说明异常是由于页不存在导致的,同时是在取指令时引起的。接下来#PF处理过程也修改了这个错误。

两种错误都被修正之后,代码可以正确的跳转到0x400000地址去执行了,执行的结构就是打印出线性地址0x400000被转换的过程,从结果上看之前的错误都被#PF处理过程修复了。


参考

《Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B & 3C): System Programming Guide》

《x86/x64体系探索及编程》





免费的企业级正版Windows安全管理利器——System Center 2012 Endpoint Protection

在上一篇文章中我们谈到了win8以及win8.1中超炫的主动防御功能,在这篇文章中我将带领大家来到一个你可能不太熟悉的企业级安全管理利器 - System Center 2012 Endpoint P...
  • liuyaping1115
  • liuyaping1115
  • 2013年08月08日 13:28
  • 42315

Web 应用程序常见漏洞 CSRF 的入侵检测与防范

简介: 互联网的安全问题一直存在,并且在可预见的未来中没有消弭的迹象,而在软件开发周期中,加入对产品安全问题的检测工作,将极大的提升对应安全问题解决的成本,对维护一个好的产品形象至关重,在竞争愈烈的网...
  • xysoul
  • xysoul
  • 2015年05月03日 18:57
  • 6851

Composer常见问题

安装了Composer后,运行composer --version,查看Composer的版本号。如果出现下面的提示,那么软件安装成功。 Composer version 1.2.0 2016...
  • wzx19840423
  • wzx19840423
  • 2016年11月01日 10:37
  • 293

android自定义访问权限

android 中如果我们想让我们的activity或service限制别人的访问,可以加上自定义权限,只有加上我们定义的权限才能访问我们的组件,具体在我们应用中的AndroidManifest.xm...
  • xiafangxingg
  • xiafangxingg
  • 2016年12月09日 11:02
  • 660

dmesg命令处理故障和收集系统信息的7种用法

http://oss.org.cn/html/52/n-86352.html ‘dmesg’命令显示linux内核的环形缓冲区信息,我们可以从中获得诸如系统架构、cpu、挂载的硬件,RAM等多个...
  • onlyForCloud
  • onlyForCloud
  • 2015年07月29日 14:31
  • 438

基于Tomcat 的WEB Project存在的安全漏洞总结

1 检查工具:Acunetix Web Vulnerability Scanner V9破解版 2 检查漏洞说明结果显示: 2.1 HTML Form Without CSRF Protection ...
  • jun55xiu
  • jun55xiu
  • 2015年01月16日 19:02
  • 12401

oracle11g broker使用的过程遇到的几个问题

1主库开了flashback,从库没有开启,结果broker就连不上从库了,提示如下: DGMGRL> show configuration verbose;Configuration - Prod...
  • aoerqileng
  • aoerqileng
  • 2016年11月26日 17:43
  • 1013

Android 4.4 Graphic系统详解(4)HWUI概述

1 概述 Android从3.0(API Level 11)开始,在绘制View的时候支持硬件加速,充分利用GPU的特性,使得绘制更加平滑。 实质上就是Android3.0以前,几乎所有的图形绘制都...
  • michaelcao1980
  • michaelcao1980
  • 2015年01月28日 17:48
  • 11483

卸载Symantec Endpoint Protection, 无需密码的卸载方法

最近一次偶然的机会, 被人装了个Symantec在电脑上, 搞得各种报警, 验证, 烦死.  然后就自然而然的想卸载掉这个该死的杀毒软件, 没想到这个杀毒软件居然还是个流氓杀毒软件, 卸载还需要密码...
  • kj619899271
  • kj619899271
  • 2013年03月15日 14:45
  • 93575

分布式服务弹性框架“Hystrix”实践与源码研究(一)

文章初衷 为了应对将来在线(特别是无线端)业务量的成倍增长,后端服务的分布式化程度需要不断提高,对于服务的延迟和容错管理将面临更大挑战,公司框架和开源团队选择内部推广Netflix的Hystrix,...
  • zhao9tian
  • zhao9tian
  • 2016年08月18日 15:21
  • 697
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Protection 6 ---- Page-Level Protection
举报原因:
原因补充:

(最多只允许输入30个字)