переписать malloc / free в библиотеке dlopen-ed - PullRequest
0 голосов
/ 24 января 2019

У меня есть общая библиотека - plugin.so, которая dlopen -едана хост-программой с флагом RTLD_LOCAL, у меня есть собственные функции работы с памятью, определенные в этой библиотеке:

void *plugin_malloc(size_t size) { /* ... */ }
void plugin_free(void *ptr) { /* ... */ }

Мне нужно заменить ВСЕ malloc/free вызовы в plugin.so на свои plugin_malloc/plugin_free, я попытался использовать расширение атрибута псевдонима GCC:

void *malloc(size_t) __attribute__((alias("plugin_malloc"), used))
void free(void*) __attribute__((alias("plugin_free"), used))

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

Я работаю в Linux с компилятором GCC-4.8.5, и у меня есть исходный код plugin.so, и я могу изменить его, как мне нравится, но я не могу изменить хост-программу и заменить malloc/free допустимо не только в plugin.so, но и во всей программе.

Итак, есть ли решение? Спасибо.


EDIT: У меня также нет разрешения изменять аргументы запуска программы хоста, переменные среды , я могу просто предоставить plugin.so парням, которые владеют программой хоста, и они запускают хост-программа и dlopen my plugin.so.

Ответы [ 2 ]

0 голосов
/ 25 января 2019

Мне нужно заменить ВСЕ вызовы malloc / free в plugin.so на мои собственные plugin_malloc / plugin_free,

Это тривиально.

Предположим, у вас есть foo.o и plugin_malloc.o, которые связаны в plugin.so. foo.o использует malloc и free, а plugin.o определяет plugin_malloc и plugin_free.

Тогда:

objcopy --redefine-sym malloc=plugin_malloc --redefine-sym free=plugin_free foo.o foo2.o
gcc -shared -fPIC plugin.o foo2.o -o plugin.so

Вуаля: все ссылки на malloc и free в foo.o заменены. Наслаждайтесь.

Обновление:

если я вызываю функцию glibc, которая выделяет память и должна быть освобождена в моем коде, программа вылетает. например char * s = strdup ("привет"); бесплатно (ы); потому что strdup вызывает malloc от glibc, но позже свободен мой plugin_free

Есть несколько способов, только некоторые из которых удовлетворяют другим вашим ограничениям:

  1. вы должны заменить все malloc с и free с на свои собственные для программы весь (например, через LD_PRELOAD или статически связать реализацию malloc в основной исполняемый файл) или
  2. вы должны убедиться, что вы не вызываете любую функцию, которая выделяет память через malloc, которую вы ожидаете на free позже или
  3. для любых таких вызовов stdup или asprintf и т. Д., Если вы хотите освободить эту память, вы должны вызвать __libc_free вместо plugin_free или
  4. в plugin_malloc, заполнить всю память, которую вы выделяете, 16-байтовым заголовком (для выравнивания), записать магическое число в начало блока и вернуть указатель после заголовка вызывающей стороне. В plugin_free проверьте правильность выравнивания, затем проверьте заголовок на магическое число. Если он есть, вычтите 16 из указателя и используйте остаток plugin_free, чтобы освободить память. Если магического номера там нет, предположим, что указатель не пришел от plugin_malloc, и вместо этого вызовите __libc_free.
  5. В plugin_malloc отслеживайте все блоки, которые вы когда-либо выделяли. В plugin_free проверьте этот список и используйте __libc_free, если указатель отсутствует в списке.

Поскольку у вас есть все источники для вашего плагина, решение 2 или 3 должно быть выполнимым, но, очевидно, требует, чтобы вы проверяли каждый вызов free, чтобы увидеть, откуда взялась память.

Варианты 4 и 5 не требуют такого аудита, но не отделяют чисто память, выделенную плагином, от памяти, выделенной основной программой.

Не забудьте о других способах выделения памяти: realloc, memalign, posix_memalign и т. Д.

0 голосов
/ 24 января 2019

Учитывая, что вы предоставляете пару функций с именем malloc и free (вместо plugin_malloc, например) в разделяемой библиотеке, скомпилированной с -fPIC, вам просто нужно LD_PRELOAD при вызове клиентского приложения:

LD_PRELOAD=/path/mymalloc.so executable

или экспортируйте его перед вызовом клиента:

export LD_PRELOAD=/path/mymalloc.so
executable

подробнее:

[ОБНОВЛЕНИЕ]

Учитывая, что вы не можете изменить среду, а только заменить динамическую библиотеку и ничего больше, то вы сможете:

  • найдите, где malloc / free находится в памяти
  • замените исходный код ввода функций для jmp на ваши собственные функции

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

Еще одна возможность изучения (oit?): Если код использует glibc, вы можете вместо этого попытаться предоставить __ malloc_hook в своей библиотеке.

Еще один: захватите элемент управления приложения в функции инициализации вашей библиотеки, никогда не возвращаясь из него, а затем снова запустите приложение с вашей пользовательской настройкой.

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

...