2015-03-18 5 views
1

У меня возникли проблемы с перехватом open() на Linux (Debian в моем случае). Вот это минималистичный источник C, который будет построен в общий объект:LD_PRELOAD-ed ловушки общего объекта read(), но не открыты() .. Почему?

/* Defines are needed for dlfcn.h (RTLD_NEXT) */ 
#define __USE_GNU 
#define _GNU_SOURCE 

#include <stdarg.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <dlfcn.h> 
#include <unistd.h> 

int open(char const *path, int oflag, ...) { 
    int (*real_open)(char const *, int, ...); 
    char *msg; 
    va_list args; 
    int mflag; 

    fprintf(stderr, ">>>>> in open <<<<<<\n"); 
    real_open = dlsym(RTLD_NEXT, "open"); 
    if ((msg = dlerror())) { 
     fprintf(stderr, "dlsym error: %s\n", msg); 
     exit(1); 
    } 
    va_start(args, oflag); 
    mflag = va_arg(args, int); 
    return real_open(path, oflag, mflag); 
} 

ssize_t read(int fd, void *buf, size_t count) { 
    ssize_t (*real_read)(int, void*, size_t); 
    char *msg; 

    fprintf(stderr, ">>>>> in read <<<<<\n"); 
    real_read = dlsym(RTLD_NEXT, "read"); 
    if ((msg = dlerror())) { 
     fprintf(stderr, "dlsym error: %s\n", msg); 
     exit(1); 
    } 
    return real_read(fd, buf, count); 
} 

Общий объект построен с использованием:

cc -c -fPIC -Wall funcs.c 
cc -shared -o libfuncs.so funcs.o -ldl -lc 

Теперь, когда я пытаюсь

export LD_PRELOAD=/path/to/libfuncs.so 
cat somefile 

то я вижу только на выходе - read(), который равен >>>>> in read <<<<<. Я никогда не вижу следов open(). Я проверил, что cat Makefile делает с помощью strace и достаточно точно - как open() и read() называются:

open("Makefile", O_RDONLY|O_LARGEFILE) = 3 
fstat64(3, {st_mode=S_IFREG|0644, st_size=213, ...}) = 0 
read(3, "testrun: libfuncs.so\n\tLD_PRELOAD"..., 32768) = 213 

Кстати, я проверил также с другими программами, такими как od или bash, никогда не должен перехватывать open(). Что тут происходит? Заранее спасибо ...

`

+0

два possibilites. 1) не используя библиотеку правильно, см. Справочную страницу для примера. 2) открытая функция фактически является макросом для встроенного в ОС или SHELL. – user3629249

ответ

2

Может быть, попробовать "Open64" вместо "открыть"?

1

Чтобы добавить ответ shooper, он кажется Glibc выполняет сборку уровня переименовать open() в open64() при компиляции приложения, которое вызывает open() с, например,

$ gcc -D_FILE_OFFSET_BITS=64 open.c -o open 

Добавление -S к вышеуказанной команде и проверки источника сборки в open.s показывает, что open64() действительно называют. $ gcc -E ... показывает, что это не просто переименование на основе препроцессора.

препроцессированный источник имеет этот бит, хотя, который выполняет переименование:

extern int open (const char *__file, int __oflag, ...) __asm__ ("" "open64") 
    __attribute__ ((__nonnull__ (1))); 

код, ответственный за создание этой декларации в /usr/include/fcntl.h:

#ifndef __USE_FILE_OFFSET64 
extern int open (const char *__file, int __oflag, ...) __nonnull ((1)); 
#else 
# ifdef __REDIRECT 
extern int __REDIRECT (open, (const char *__file, int __oflag, ...), open64) 
    __nonnull ((1)); 
# else 
# define open open64 
# endif 
#endif 
#ifdef __USE_LARGEFILE64 
extern int open64 (const char *__file, int __oflag, ...) __nonnull ((1)); 
#endif 

Декларация с __REDIRECT - это то, что используется здесь.

При условии, что это реальная проблема, я думаю, что Glibc в свою очередь, превращает open64() вызов в open("Makefile", O_RDONLY|O_LARGEFILE) системный вызов, который вы видите в strace. Так как вы можете только переопределять функции, а не сами системные вызовы, вы должны попробовать open64(), а не как предлагаемый shooper.

(я не знаю, почему Glibc делает это так, кстати, если это по другим причинам, чем просто избегать макросов.)