拦截对GNU tar的openat()系统调用

Jul*_*enz 5 gcc libc system-calls intercept ld-preload

我正在尝试openat()使用我可以通过加载的自定义共享库拦截Linux上的系统调用LD_PRELOAD.一个例子intercept-openat.c有这样的内容:

#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);
}
Run Code Online (Sandbox Code Playgroud)

我通过编译它gcc -fPIC -Wall -shared -o intercept-openat.so intercept-openat.c -ldl.然后,当我运行这个小示例程序时:

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;
}
Run Code Online (Sandbox Code Playgroud)

openat()通过库重新调用该调用:

$ LD_PRELOAD=./intercept-openat.so ./openat 
intercepting openat()...
Run Code Online (Sandbox Code Playgroud)

但是,GNU tar也不会发生同样的情况,即使它使用相同的系统调用:

$ 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
Run Code Online (Sandbox Code Playgroud)

所以自定义openat()来源intercept-openat.so没有被调用.这是为什么?

ams*_*ams 2

它使用相同的系统调用,但显然它不通过相同的 C 函数调用。或者,也可能是这样,但它是静态链接的。

不管怎样,我认为你已经证明它永远不会动态链接函数名称“openat”。如果您仍然想追求这个选项,您可能想看看它是否链接到该函数的特定版本,但这是一个不太可能的选择。

您仍然可以通过编写要使用的程序来拦截系统调用ptrace。这与 strace 和 gdb 使用的接口相同。但它会带来更高的性能损失。

http://linux.die.net/man/2/ptrace

  • 感谢您为我指明了正确的方向。看起来,“tar”从不调用库函数“openat()”。相反,它使用“__openat_2()”(不管那是什么)。因此,如果我添加以下行,上面的代码将适用于示例程序和 GNU tar: `int __openat_2(int dirfd, const char *pathname, int flags, mode_t mode) __attribute__((alias ("openat"))); ` 这样 `__openat_2` 是 `openat` 的别名。 (2认同)