how to check the hardware support of XN/XI bit support on ARM/MIPS platform

-1

I was verifying the hardware support of XN bit on ARM v6/v7 platform. for this I executed execstack.c on ARM. It is crashing as there is XN bit support for ARM v6/v7. Then I checked the same on MIPS target(34Kc) which does not have XI bit support and hence program must execute normally, but here also this program crashed. Then I removed XN bit code and compiled for ARM. Then also program crashed which should not.

Test Programme /* execstack.c - Tests whether code on the stack can be executed

*/

typedef void (*fptr)(void);

char *testname = "Executable stack                         ";

void itworked( void )
{
      printf( "Vulnerable\n" );
        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\n" );
                        exit( 0 );
               }
        }
        exit( 0 );
}

void itfailed( void )
{
        printf( "Ok\n" );
        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;
}

/Logs on MIPS target/

On MIPS target the execstack testcase giving below coredump although I assume that XI bit is not supported in MIPS.

VDLinux#> ./execstack

Executable stack[ 53.272000] do_ri() : sending SIGILL to execstack, PID:386

Killed

/Logs on ARM target/

VDLinux#> ./execstack

Executable stack[ 451.784000] execstack: unhandled page fault (11) at 0xbead5860, code 0x80000007 Killed

So I have following questions:

  1. How to verify XN bit support on ARM v6/V7?
  2. How to verify XI bit support on MIPS 34Kc
  3. Where to check XN bit support in Linux Kernel Code.

Thanks, Girish

arm
pax
dep
asked on Stack Overflow Jan 3, 2013 by Girish Gupta • edited May 1, 2019 by Bhargav Rao

1 Answer

2

I have written the below assembly code to test XN bit support on ARM target.

.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\n   "

Generating machine from assembly:

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

Disassembly of section .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 

Final Shell Code in C:

#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[] = "\x01\x00\xa0\xe3\x14\x10\x8f\xe2"
    "\x0c\x20\xa0\xe3\x04\x70\xa0\xe3"
    "\x00\x00\x00\xef\x00\x00\xa0\xe3"
    "\x01\x70\xa0\xe3\x00\x00\x00\xef" "hello world\n   \0";

  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) ();
}

Case 1: When stack is executable:

Compilation of program:

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

Reading ELF header:

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

Running the program: As here stack is executable so XN bit will be cleared (0). And program will run normally.

ARM_Target#> ./stack_RWX
hello world

Case 2: When stack is non executable:

Compilation of program:

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

Reading ELF header:

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

Running the program: As here XN bit is set (it is 1), so we will get segmentation fault in each case.

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)

Patch for Disabling XN bit in ARM: I have created a patch. In this patch we comment a section of assembly code. This is done in arch/arm/mm/proc-v7.S

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

If I deselect CONFIG_XN_SUPPORT option PTE_EXT_XN bit will be always be 0. So all binaries will be executed, whether the stack is executable or not.

Running the program:

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

Conclusion:
XN bit is supported in Cortex-A15 ARMv7.

answered on Stack Overflow Jan 21, 2013 by Girish Gupta

User contributions licensed under CC BY-SA 3.0