Search code examples
csystem-callsld-preloadsystrace

LD_PRELOAD can not intercept syscalls, but only libcalls?


My code works well with malloc, but not with mmap. The code is below:

main.c

#include <stdio.h>
#include <stdlib.h>

int main(){
  int * p = (int*) malloc(sizeof(int));
  printf("in main(): value p = %d\n", *p);
  free(p);
}

preload.c

#define _GNU_SOURCE
#include <time.h>
#include <dlfcn.h>
#include <stdio.h>
#include <sys/types.h>

void *(*orig_malloc)(size_t size);
void *malloc(size_t size){
  printf("  Hooked(preload)! malloc:size:%lu\n", size);
  return orig_malloc(size);
}

void * (*orig_mmap)(void *start, size_t length, int prot, int flags, int fd, off_t offset);
void * mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset){
  printf("  Hooked(preload)! mmap:start:%p, length:%lu, prot:%d, flags:%p, fd:%p, offset:%d\n", start, length, prot, flags, fd, offset);
  return orig_mmap(start, length, prot, flags, fd, offset);
}

void
_init(void)
{
  printf("Loading hack.\n");
  orig_malloc = (void* (*)(size_t)) dlsym(RTLD_NEXT, "malloc");
  orig_mmap = (void* (*)(void*, size_t, int, int, int, off_t)) dlsym(RTLD_NEXT, "mmap");
}

to compile it

gcc -Wall -fPIC -DPIC -c preload.c
ld -shared -o preload.so preload.o -ldl
gcc main.c

to run it with LD_PRELOAD

LD_PRELOAD=./preload.so ./a.out

to run it with strace

strace ./a.out 2>&1 | view -

the printout from LD_PRELOAD does not hook calls to mmap, but only calls to malloc. Meanwhile, when running with strace, the printout does show mmap is called multiple times.

This result baffles me; assuming mmap is indeed called by main.c (I guess through malloc), how come preload.c can not intercept mmap?

PS: My platform is Ubuntu 14.04 with Linux kernel 3.13

PS2: By syscall, I mean the syscall wrapper in libc (not sure if this makes a difference to the question though)..


Solution

  • mmap is a syscall, malloc is not.

    Since syscalls are essential for the functioning of a program, they must work before ld.so actually springs into action, they are reside in a section that gets loaded before everything else; it may be linked dynamically, but that mapping (of that particular "virtual" dynamic object) is done by the kernel itself. Looong before ld.so actually gets to work.