Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I reimplement (or wrap) a syscall function on Linux?

Suppose I want to completely take over the open() system call, maybe to wrap the actual syscall and perform some logging. One way to do this is to use LD_PRELOAD to load a (user-made) shared object library that takes over the open() entry point.

The user-made open() routine then obtains the pointer to the glibc function open() by dlsym()ing it, and calling it.

The solution proposed above is a dynamic solution, however. Suppose I want to link my own open() wrapper statically. How would I do it? I guess the mechanism is the same, but I also guess there will be a symbol clash between the user-defined open() and the libc open().

Please share any other techniques to achieve the same goal.

like image 600
Stefano Borini Avatar asked Sep 07 '10 21:09

Stefano Borini


People also ask

What is syscall wrapper?

Here, the primary function of the wrapper is to place all the arguments to be passed to the system call in the appropriate processor registers (and maybe on the call stack as well), and also setting a unique system call number for the kernel to call.

Where is syscall in Linux?

Roughly speaking, the code belonging to the system call with number __NR_xxx defined in /usr/include/asm/unistd. h can be found in the Linux kernel source in the routine sys_xxx().

What is syscall in Linux?

As the name suggests, syscalls are system calls, and they're the way that you can make requests from user space into the Linux kernel. The kernel does some work for you, like creating a process, then hands control back to user space.


1 Answers

You can use the wrap feature provided by ld. From man ld:

--wrap symbol Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to __wrap_symbol.

Any undefined reference to __real_symbol will be resolved to symbol.

So you just have to use the prefix __wrap_ for your wrapper function and __real_ when you want to call the real function. A simple example is:

malloc_wrapper.c:

#include <stdio.h> void *__real_malloc (size_t);  /* This function wraps the real malloc */ void * __wrap_malloc (size_t size) {     void *lptr = __real_malloc(size);     printf("Malloc: %lu bytes @%p\n", size, lptr);     return lptr; } 

Test application testapp.c:

#include <stdio.h> #include <stdlib.h> int main() {     free(malloc(1024)); // malloc will resolve to __wrap_malloc     return 0; } 

Then compile the application:

gcc -c malloc_wrapper.c gcc -c testapp.c gcc -Wl,-wrap,malloc testapp.o malloc_wrapper.o -o testapp 

The output of the resulting application will be:

$ ./testapp Malloc: 1024 bytes @0x20d8010 
like image 83
Giuseppe Cardone Avatar answered Sep 22 '22 07:09

Giuseppe Cardone