在Linux上,为什么这个用LD_PRELOAD加载的库只能捕获一些openat()调用?

时间:2018-02-07 06:54:57

标签: linux linux-kernel ld-preload

我正在尝试使用以下库openat()拦截comm.c次调用。这是非常标准的最小例子,没什么特别之处。我用

编译它
>gcc -shared -Wall -fPIC -Wl,-init,init  comm.c -o comm.so

我正在粘贴这个标准的最小例子来表明,我想,我知道自己在做什么。

#define _GNU_SOURCE
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>

typedef int (*openat_type)(int, const char *, int, ...);

static openat_type g_orig_openat;

void init() {
    g_orig_openat = (openat_type)dlsym(RTLD_NEXT,"openat");
}

int openat(int dirfd, const char* pathname, int flags, ...) {
    int fd;
    va_list ap;

    if (flags & (O_CREAT)) {
            va_start(ap, flags);
            fd = g_orig_openat(dirfd, pathname, flags, va_arg(ap, mode_t));
        }
    else
        fd = g_orig_openat(dirfd, pathname, flags);

    printf("openat dirfd %d pathname %s\n", dirfd, pathname);

    return fd;
}

我正在运行tar命令,这是一个最小的示例,将包含单个文件foobar的存档解压缩到预先存在的子目录dir

>strace -f tar xf foobar.tar -C dir 2>&1 | grep openat
openat(AT_FDCWD, "dir", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 4
openat(4, "foobar", O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_NONBLOCK|O_CLOEXEC, 0600) = -1 EEXIST (File exists)
openat(4, "foobar", O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_NONBLOCK|O_CLOEXEC, 0600) = 5

然而,

>LD_PRELOAD=./comm.so tar xf foobar.tar -C dir
openat dirfd 4 pathname foobar
openat dirfd 4 pathname foobar

好的,我知道如何处理这个 - 我以前做过这个 - 这种差异的原因是openat()显示的系统调用strace不是由openat()完成的同名用户函数tar。要找出其他用户函数是什么,可以获取源代码,重建它们并查找。

所以,我得到了>$(which tar) --version tar (GNU tar) 1.26 的来源:

tar

我得到了tar 1.26个来源并自己重建了它们,而且,如果我使用我构建的二进制comm.so而不是上面安装的二进制openat,那么{{1}确实捕获了所有3个{{1}}来电!

这意味着没有&#34;其他用户功能&#34;。

请帮忙,这里可能会发生什么?

不,之前的问题没有回答这个问题。前面的回答简单地说,库调用可能与底层系统调用的名称不同。在这里,情况并非如此,因为我自己重新编译了相同的代码,并且没有其他库调用。

1 个答案:

答案 0 :(得分:0)

根据所提到的讨论,openat 可能会被不同的符号或函数调用。 strace 等工具转储的系统调用是原始系统调用。它可能由用户函数或 glibc 包装。如果你想通过 LD_PRELOAD 拦截它,你需要找出那些包装器而不是 openat。根据我的经验,您可以尝试拦截 open64open,它可以重定向到您在 openat 上观察到的 strace

link 是从 openat 包装 open64 的一个示例。