Функция system() не вызывается из библиотеки LD_PRELOAD

Я пытаюсь использовать LD_PRELOAD на Linux, чтобы обернуть звонки system функция, чтобы добавить некоторую предварительную обработку к аргументу. Вот мой system.cpp:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <string>
#include <iostream>

typedef int (*orig_system_type)(const char *command);

int system(const char *command)
{
    std::string new_cmd = std::string("set -f;") + command;
    // next line is for debuggin only
    std::cout << new_cmd << std::endl;

    orig_system_type orig_system;
    orig_system = (orig_system_type)dlsym(RTLD_NEXT,"system");
    return orig_system(new_cmd.c_str());
}

Я строю это с

g++ -shared -fPIC -ldl -o libsystem.so system.cpp

который производит объект.so. Затем я запускаю свою программу с

$ LD_PRELOAD=/path/to/libsystem.so ./myprogram

Я не получаю никаких ошибок - но, похоже, мой system функция не вызывается. Бег с LD_DEBUG=libs, Я вижу, что мой.so загружается, однако мой system функция не вызывается, а вызывается функция из стандартной библиотеки.

Что мне нужно изменить в коде / сборке, чтобы заставить его работать?

3 ответа

Решение

Тебе нужно

extern "C" int system ...

потому что он вызывается функцией C. Версия C++ имеет искаженное имя, поэтому она не распознается.

Возможно, вы захотите сохранить указатель "orig_system", чтобы избежать вызова dlsym каждый раз. Вы можете сделать это в функции конструктора / инициализации, чтобы у вас было что-то вроде

extern "C" {

typedef int (*orig_system_type)(const char *command);

static orig_system_type orig_system;

static void myInit() __attribute__((constructor));

void myInit()
{
    orig_system = (orig_system_type)dlsym(RTLD_NEXT,"system");
}

int system(const char *command)
{
    std::string new_cmd = std::string("set -f;") + command;
    // next line is for debuggin only
    std::cout << new_cmd << std::endl;
    return orig_system(new_cmd.c_str());
}

}

(этот код не проверен, но я использовал эту технику в прошлом).

Альтернативой может быть использование опции --wrap GNU ld.

Если вы компилируете свою общую библиотеку с

-Wl,- система обертывания

тогда в своем коде ты пишешь

extern "C" {

void* __real_system(const char* command);
void* __wrap_system(const char* command)
{
    std::string new_cmd = std::string("set -f;") + command;
    // next line is for debuggin only
    std::cout << new_cmd << std::endl;
    return __real_system(new_cmd.c_str());
}

}

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

Код должен работать отлично. Предполагая, что программа драйвера выглядит примерно так:

#include <cstdlib>

int main() {
    system("find -name *.cpp");
}

затем env LD_PRELOAD=$PWD/libsystem.so ./a.out дает мне этот вывод:

set -f;find -name *.cpp
./system.cpp
./test.cpp

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

Другие вопросы по тегам