如何在ARM / MIPS平台上检查XN / XI位支持的硬件支持

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在ARM / MIPS平台上检查XN / XI位支持的硬件支持相关的知识,希望对你有一定的参考价值。

我正在验证ARM v6 / v7平台上XN位的硬件支持。为此我在ARM上执行了execstack.c。由于ARM v6 / v7支持XN位,因此崩溃了。然后我在MIPS目标(34Kc)上检查了相同的,它没有XI位支持,因此程序必须正常执行,但是这里程序也崩溃了。然后我删除了XN位代码并为ARM编译。然后程序崩溃,不应该。

测试程序/ * execstack.c - 测试堆栈上的代码是否可以执行

*/

typedef void (*fptr)(void);

char *testname = "Executable stack                         ";

void itworked( void )
{
      printf( "Vulnerable
" );
        exit( 1 );
}

void doit( void )
{
       char buf[8192];
        fptr func;
        /* Put a RETN instruction in the buffer */
        buf[0] = 'xc3';
        /* Convert the pointer to a function pointer */
        func = (fptr)buf;
        /* Call the code in the buffer */
        func();
        /* It worked when the function returns */
        itworked();
}

int main( int argc, char *argv[] )
{
       int status;
        printf( "%s: ", testname );
        fflush( stdout );
        if( fork() == 0 ) {
                do_mprotect((unsigned long)argv & ~4095U, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
                doit();
        } else {
                wait( &status );
                if( WIFEXITED(status) == 0 ) {
                        printf( "Killed
" );
                        exit( 0 );
               }
        }
        exit( 0 );
}

void itfailed( void )
{
        printf( "Ok
" );
        exit( 2 );
}

int do_mprotect( const void *addr, size_t len, int prot )
{
        void *ptr;
        int retval;
        /* Allign to a multiple of PAGESIZE, assumed to be a power of two */
        ptr = (char *)(((unsigned long) addr) & ~(PAGESIZE-1));
         retval = mprotect( ptr, len, prot );
        if( retval != 0 && errno == EINVAL ) {
                perror( "could not mprotect():" );
                exit( 1 );
    }
         return retval;
}

/登录MIPS目标/

在MIPS上,execstack测试用例给出了下面的coredump,尽管我假设MIPS不支持XI位。

VDLinux#> ./execstack

可执行堆栈[53.272000] do_ri():将SIGILL发送到execstack,PID:386

杀害

/登录ARM目标/

VDLinux#> ./execstack

可执行堆栈[451.784000] execstack:0xbead5860处的未处理页错(11),代码0x80000007已杀

所以我有以下问题:

  1. 如何验证ARM v6 / V7上的XN位支持?
  2. 如何验证MIPS 34Kc上的XI位支持
  3. 在Linux内核代码中检查XN位支持的位置。

谢谢,Girish

答案

我编写了下面的汇编代码来测试ARM目标上的XN位支持。

.text
.global _start
_start:
mov   r0, #1        (output)    
add   r1, pc, #20   (string)
mov   r2, #12        strlen(string))
mov   r7, #4        (syscall number for write)
svc   0x0

mov   r0, #0        (output)    
mov   r7, #1        (syscall number for exit)
svc   0x0
.asciz  "Hello world
   "

从装配生成机器:

arm-linux-gnueabi-gcc -c -o arm_hello.o arm_hello.s
arm-linux-gnueabi-ld arm_hello.o -o arm_hello

反汇编.text:

root@oss:shellcode_2# arm-linux-gnueabi-objdump -d arm_hello 
arm_hello :     file format elf32-littlearm
00008054 <_start>:
8054:       e3a00001        mov     r0, #1
8058:       e28f1014        add     r1, pc, #20
805c:       e3a0200c        mov     r2, #12
8060:       e3a07004        mov     r7, #4
8064:       ef000000        svc     0x00000000
8068:       e3a00000        mov     r0, #0
806c:       e3a07001        mov     r7, #1
8070:       ef000000        svc     0x00000000
8074:       6c6c6548        .word   0x6c6c6548
8078:       6f77206f        .word   0x6f77206f
807c:       0a646c72        .word   0x0a646c72
8080:       00202020        .word   0x00202020 

C中的最终Shell代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <asm/unistd.h>

typedef void (*fptr) (void);

void
main ()
{
  unsigned char hellocode[] = "x01x00xa0xe3x14x10x8fxe2"
    "x0cx20xa0xe3x04x70xa0xe3"
    "x00x00x00xefx00x00xa0xe3"
    "x01x70xa0xe3x00x00x00xef" "hello world
   ";

  unsigned char buffcode[256] __attribute__ ((aligned (32)));
  fptr func;

  memcpy (buffcode, hellocode, 49);

  /* Convert the pointer to a function pointer */
  func = (fptr) buffcode;

  /* flush contents of instruction and/or data cache */
  syscall (__ARM_NR_cacheflush, buffcode, buffcode + 50, 0);

  /* Call the code in the buffer */
  (*func) ();
}

案例1:当堆栈可执行时:

程序汇编:

root@oss:shellcode_ final# arm-linux-gnueabi-gcc stack.c -z execstack -o stack_RWX

阅读ELF标题:

root@oss:shellcode_final# arm-v7a9v3r0-linux-gnueabi-readelf -l stack_RWX 
Elf file type is EXEC (Executable file)
Program Headers:
Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4

运行程序:此处堆栈是可执行的,因此XN位将被清除(0)。程序将正常运行。

ARM_Target#> ./stack_RWX
hello world

情况2:当堆栈不可执行时:

程序汇编:

root@oss:shellcode_ final# arm-v7a15v3r1-linux-gnueabi-gcc stack.c -o stack_RW

阅读ELF标题:

root@oss:shellcode_final# arm-linux-gnueabi-readelf -l stack_RW
Elf file type is EXEC (Executable file)
Program Headers:
Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

运行程序:由于此处XN位已设置(它为1),因此我们将在每种情况下获得分段错误。

ARMtarget#> ./stack_RW
[   39.092000] stack_RW: unhandled page fault (11) at 0xbeca8760, code 0x8000000f
[   41.000000] [VDLP COREDUMP] SIGNR:11
Segmentation fault (core dumped)

在ARM中禁用XN位的补丁:我创建了一个补丁。在这个补丁中,我们评论了汇编代码的一部分。这是在arch / arm / mm / proc-v7.S中完成的

#ifdef CONFIG_XN_SUPPORT
   tst  r1, #L_PTE_XN
   orrne    r3, r3, #PTE_EXT_XN
#endif

如果取消选择CONFIG_XN_SUPPORT选项,PTE_EXT_XN位将始终为0.因此,无论堆栈是否可执行,都将执行所有二进制文件。

运行程序:

ARM_Target#> ./stack_RWX
hello world
ARM_Target#> ./stack_RW 
hello world

结论: Cortex-A15 ARMv7支持XN位。

以上是关于如何在ARM / MIPS平台上检查XN / XI位支持的硬件支持的主要内容,如果未能解决你的问题,请参考以下文章

ARM 处理器上的 MIPS 计算

基于MIPS ARM架构平台, Ubuntu20.xx版本下交叉编译Qt5.12.xtslib-1.4

基于MIPS ARM架构平台, Ubuntu20.xx版本下交叉编译Qt5.12.xtslib-1.4

ARM、MIPS、x86 的 Android os.arch 输出?

让nodejs跑在arm或者mips,mipsel的路由上有意义么

如何在Linux下用QT creator搭建mips-linux交叉编译开发环境,如果您熟悉ARM-linux环境搭建的话也希望你能指