перехват системного вызова openat() для GNU tar

Я пытаюсь перехватить системный вызов 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);
}

Я компилирую через 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;
}

Вызов openat() переписан через библиотеку:

$ LD_PRELOAD=./intercept-openat.so ./openat 
intercepting openat()...

Однако с 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

Так что кастомный openat() из intercept-openat.so не вызывается. Почему это?


person Julius Plenz    schedule 06.02.2012    source источник


Ответы (1)


Он использует тот же системный вызов, но, по-видимому, не вызывает его через ту же функцию C. В качестве альтернативы может быть так, но оно статически связано.

В любом случае, я думаю, вы доказали, что он никогда не связывает динамически имена функций «openat». Если вы по-прежнему хотите использовать этот вариант, вам может быть интересно узнать, ссылается ли он на конкретную версию этой функции, но это далеко не так.

Вы все еще можете перехватить системный вызов, написав свою программу для использования ptrace. Это тот же интерфейс, который используется strace и gdb. Однако это будет иметь более высокий штраф за производительность.

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

person ams    schedule 06.02.2012
comment
Спасибо, что указали мне правильное направление. 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. - person Julius Plenz; 06.02.2012
comment
Кроме того, кажется, что правильным инструментом для выполнения этой работы является ltrace (как в трассировке вызовов библиотеки). - person Julius Plenz; 07.02.2012