Как я могу обнаружить доступ к файлам в Linux? - PullRequest
10 голосов
/ 19 мая 2009

У меня есть куча потоков и приложений для обработки данных, которые мне иногда нужно шпионить, то есть мне нужно знать, какие файлы они читают. Это в основном помогает в упаковке тестовых наборов, но также может быть полезно при отладке.

Есть ли способ запустить исполняемые файлы таким образом, чтобы создать такой список?

У меня есть две мысли по этому поводу:

  1. Существует команда, которую я могу вызвать, и эта команда вызывает мои приложения. Нечто подобное GDB. Я вызываю GDB, указываю путь к исполняемому файлу и некоторые аргументы, и GDB вызывает его для меня. Возможно, есть что-то похожее на рассказ о том, как используются системные ресурсы.
  2. Возможно, более интересное (но ненужное побочное решение) решение.
    1. создать библиотеку с именем libc.so, которая реализует fopen (и некоторые другие)
    2. изменить LD_LIBRARY_PATH, чтобы он указывал на новую библиотеку
    3. сделайте копию реального libc.so и переименуйте fopen (возможно, nepof) в редакторе
    4. моя библиотека загружает копию и при необходимости вызывает переименованную функцию для обеспечения функциональности fopen.
    5. вызвать приложение, которое затем вызывает мой прокси-сервер.

Альтернатива № 1, безусловно, будет предпочтительнее, но комментарии о том, как сделать № 2 проще, также приветствуются.

Ответы [ 3 ]

13 голосов
/ 19 мая 2009

Один из вариантов - использовать strace:

strace -o logfile -eopen yourapp

Это будет регистрировать все события открытия файлов, но налагает снижение производительности, которое может быть значительным. Тем не менее, он прост в использовании.

Другой вариант - использовать LD_PRELOAD. Это соответствует вашему варианту №2. Основная идея - сделать что-то вроде этого:

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>

int open(const char *fn, int flags) {
    static int (*real_open)(const char *fn, int flags);

    if (!real_open) {
        real_open = dlsym(RTLD_NEXT, "open");
    }

    fprintf(stderr, "opened file '%s'\n", fn);
    return real_open(fn, flags);
}

Затем построить с:

gcc -fPIC -shared -ldl -o preload-example.so preload-example.c

И запустите вашу программу, например:

$ LD_PRELOAD=$PWD/preload-example.so cat /dev/null
opened file '/dev/null'

Это намного меньше накладных расходов.

Обратите внимание, однако, что существуют другие точки входа для открытия файлов - например, fopen (), openat () или одна из многих устаревших точек входа совместимости:

00000000000747d0 g    DF .text      000000000000071c  GLIBC_2.2.5 _IO_file_fopen
0000000000068850 g    DF .text      000000000000000a  GLIBC_2.2.5 fopen
000000000006fe60 g    DF .text      00000000000000e2  GLIBC_2.4   open_wmemstream
00000000001209c0  w   DF .text      00000000000000ec  GLIBC_2.2.5 posix_openpt
0000000000069e50 g    DF .text      00000000000003fb  GLIBC_2.2.5 _IO_proc_open
00000000000dcf70 g    DF .text      0000000000000021  GLIBC_2.7   __open64_2
0000000000068a10 g    DF .text      00000000000000f5  GLIBC_2.2.5 fopencookie
000000000006a250 g    DF .text      000000000000009b  GLIBC_2.2.5 popen
00000000000d7b10  w   DF .text      0000000000000080  GLIBC_2.2.5 __open64
0000000000068850 g    DF .text      000000000000000a  GLIBC_2.2.5 _IO_fopen
00000000000d7e70  w   DF .text      0000000000000020  GLIBC_2.7   __openat64_2
00000000000e1ef0 g    DF .text      000000000000005b  GLIBC_2.2.5 openlog
00000000000d7b10  w   DF .text      0000000000000080  GLIBC_2.2.5 open64
0000000000370c10 g    DO .bss       0000000000000008  GLIBC_PRIVATE _dl_open_hook
0000000000031680 g    DF .text      0000000000000240  GLIBC_2.2.5 catopen
000000000006a250 g    DF .text      000000000000009b  GLIBC_2.2.5 _IO_popen
0000000000071af0 g    DF .text      000000000000026a  GLIBC_2.2.5 freopen64
00000000000723a0 g    DF .text      0000000000000183  GLIBC_2.2.5 fmemopen
00000000000a44f0  w   DF .text      0000000000000088  GLIBC_2.4   fdopendir
00000000000d7e70 g    DF .text      0000000000000020  GLIBC_2.7   __openat_2
00000000000a3d00  w   DF .text      0000000000000095  GLIBC_2.2.5 opendir
00000000000dcf40 g    DF .text      0000000000000021  GLIBC_2.7   __open_2
00000000000d7b10  w   DF .text      0000000000000080  GLIBC_2.2.5 __open
0000000000074370 g    DF .text      00000000000000d7  GLIBC_2.2.5 _IO_file_open
0000000000070b40 g    DF .text      00000000000000d2  GLIBC_2.2.5 open_memstream
0000000000070450 g    DF .text      0000000000000272  GLIBC_2.2.5 freopen
00000000000318c0 g    DF .text      00000000000008c4  GLIBC_PRIVATE __open_catalog
00000000000d7b10  w   DF .text      0000000000000080  GLIBC_2.2.5 open
0000000000067e80 g    DF .text      0000000000000332  GLIBC_2.2.5 fdopen
000000000001e9b0 g    DF .text      00000000000003f5  GLIBC_2.2.5 iconv_open
00000000000daca0 g    DF .text      000000000000067b  GLIBC_2.2.5 fts_open
00000000000d7d60  w   DF .text      0000000000000109  GLIBC_2.4   openat
0000000000068850  w   DF .text      000000000000000a  GLIBC_2.2.5 fopen64
00000000000d7d60  w   DF .text      0000000000000109  GLIBC_2.4   openat64
00000000000d6490 g    DF .text      00000000000000b6  GLIBC_2.2.5 posix_spawn_file_actions_addopen
0000000000121b80 g    DF .text      000000000000008a  GLIBC_PRIVATE __libc_dlopen_mode
0000000000067e80 g    DF .text      0000000000000332  GLIBC_2.2.5 _IO_fdopen

Вам может понадобиться подключить все это для полноты - по крайней мере, те, которые не имеют префикса _, должны быть подключены. В частности, обязательно подключите fopen отдельно , так как внутренний вызов libc из fopen () к open () не перехватывается библиотекой LD_PRELOAD.

Аналогичное предостережение применимо к strace - также есть системный вызов 'openat', и в зависимости от вашей архитектуры могут быть и другие устаревшие системные вызовы. Но не так много, как с хуками LD_PRELOAD, поэтому, если вы не возражаете против снижения производительности, это может быть более простой вариант.

4 голосов
/ 19 мая 2009
man strace 

пример (предположим, 2343 - идентификатор процесса):

# logging part
strace -p 2343 -ff -o strace_log.txt 

# displaying part
grep ^open strace_log.txt
2 голосов
/ 19 мая 2009

Я использую что-то вроде:

strace -o file.txt ./command

Вы можете

cat file.txt | grep open

, чтобы получить список всех файлов, которые открыла программа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...