I'm trying to intercept the openat()
system call on Linux using a custom shared library that I can load via LD_PRELOAD
. An example intercept-openat.c
has this content:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <dlfcn.h>
int (*_original_openat)(int dirfd, const char *pathname, int flags, mode_t mode);
void init(void) __attribute__((constructor));
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
void init(void)
{
_original_openat = (int (*)(int, const char *, int, mode_t))
dlsym(RTLD_NEXT, "openat");
}
int openat(int dirfd, const char *pathname, int flags, mode_t mode)
{
fprintf(stderr, "intercepting openat()...\n");
return _original_openat(dirfd, pathname, flags, mode);
}
I compile it via gcc -fPIC -Wall -shared -o intercept-openat.so intercept-openat.c -ldl
. Then, when I run this small example program:
int main(int argc, char *argv[])
{
int fd;
fd = openat(AT_FDCWD, "/home/feh/.vimrc", O_RDONLY);
if(fd == -1)
return -1;
close(fd);
return 0;
}
The openat()
call is re-written via the library:
$ LD_PRELOAD=./intercept-openat.so ./openat
intercepting openat()...
However, the same does not happen with GNU tar, even though it uses the same system call:
$ strace -e openat tar cf /tmp/t.tgz .vimrc
openat(AT_FDCWD, ".vimrc", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC) = 4
$ LD_PRELOAD=./intercept-openat.so tar cf /tmp/t.tgz .vimrc
So the custom openat()
from intercept-openat.so
is not being called. Why is that?
tar
never calls the library functionopenat()
, as it seems. Instead, it uses__openat_2()
(whatever the heck that is). So the above code will work for both the example program and GNU tar if I add this line:int __openat_2(int dirfd, const char *pathname, int flags, mode_t mode) __attribute__((alias ("openat")));
such that__openat_2
is an alias foropenat
. – Fake