1

I write a sample code on x86_64,try to execute dynamiclly malloc code. there is a

Program received signal SIGSEGV, Segmentation fault. 0x0000000000601010 in ?? ()

0x0000000000601010 is the position of bin,someone can tell why? thanks!!

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <sys/mman.h>
volatile int sum(int a,int b)
{
    return a+b;
}

int main(int argc, char **argv)
{
   char* bin = NULL;    
   unsigned int len = 0;
   int ret = 0;
   /*code_str is the compiled code for function sum.*/
   char code_str[] ={0x55,0x48,0x89,0xe5,0x89,0x7d,0xfc,0x89,
          0x75,0xf8,0x8b,0x45,0xf8,0x03,0x45,0xfc,0xc9,0xc3};
   len = sizeof(code_str)/sizeof(char);
   bin = (char*)malloc(len);
   memcpy(bin,code_str,len);
   mprotect(bin,len , PROT_EXEC | PROT_READ | PROT_WRITE);
   asm volatile ("mov $0x2,%%esi \n\t"
        "mov $0x8,%%edi \n\t"
        "mov %1,%%rbx \n\t"
        "call *%%rbx "
        :"=a"(ret)
        :"g"(bin)
        :"%rbx","%esi","%edi");

   printf("sum:%d\n",ret);
   return 0;
}
Nico Erfurth
  • 3,362
  • 22
  • 26
hellolwq
  • 531
  • 3
  • 7
  • 18

2 Answers2

2

Never do such tricks without checking the return of system functions. My man page for mprotect says in particular:

   POSIX  says  that  the  behavior of mprotect() is unspecified if it
   is applied to a region of memory that was not obtained via mmap(2).

so don't do that with malloced buffers.

Also:

  • The buffer size is just sizeof(code_str), there is no reason to divide by sizeof(char) (which is guaranteed to be 1, but that doesn't make it correct).
  • There's no need to cast the return of malloc (nor mmap if you change it to that).
  • The correct type for code_str is unsigned char and not char.
Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • You're welcome. But thinking of it, the main error was probably the thing with `&bin` as people say in the comments. `0x0000000000601010` doesn't look like a `malloc`ed address. – Jens Gustedt Aug 05 '12 at 07:02
0

the question is that bin address should align to multiple PAGESIZE,or mprotect will return -1,arguments invalid.

   bin = (char *)(((int) bin + PAGESIZE-1) & ~(PAGESIZE-1));//added....
   memcpy(bin,code_str,len);
   if(mprotect(bin, len , PROT_EXEC |PROT_READ | PROT_WRITE) == -1)
   {
     printf("mprotect error:%d\n",errno);
     return 0;
   }
hellolwq
  • 531
  • 3
  • 7
  • 18
  • 1
    If the region in question crosses a page boundary, this will fail to set the protections for both pages correctly. – Dietrich Epp Aug 05 '12 at 07:10