мой код следующие: preload.c, со следующим содержанием:
#include <stdio.h>
#include <stdlib.h>
int __attribute__((constructor)) main_init(void)
{
printf("Unsetting LD_PRELOAD: %x\n",unsetenv("LD_PRELOAD"));
FILE *fp = popen("ls", "r");
pclose(fp);
}
затем в оболочке (делают 2-ю команду с осторожностью!!):
gcc preload.c -shared -Wl,-soname,mylib -o mylib.so -fPIC
LD_PRELOAD=./mylib.so bash
!!! будьте осторожны с последней командой, она закончится с бесконечным циклом разветвления "sh-c ls". Остановите его после 2 секунд с ^C, (или лучше ^Z и затем посмотрите PS).
если Вы используете:
LD_DEBUG=all LD_DEBUG_OUTPUT=/tmp/ld-debug LD_PRELOAD=./mylib.so bash
вместо последней команды Вы получите много файлов ld-отладки, названных/tmp/ld-debug.*. Один для каждого разветвленного процесса. ВО ВСЕХ ЭТИХ ФАЙЛАХ Вы будете видеть, что символы сначала ищутся в mylib.so даже при том, что LD_PRELOAD был удален из среды.
редактировать: так что проблема / вопрос на самом деле заключалась в следующем: как вы не можете надежно отключить LD_PRELOAD
с помощью предварительно загруженного main_init ()
изнутри bash
.
Причина в том, что execve
, который вызывается после того, как вы popen
, берет среду из (вероятно)
extern char **environ;
, которая представляет собой некоторую глобальную переменную состояния, указывающую на ваше окружение. unsetenv ()
обычно изменяет вашу среду и, следовательно, влияет на содержимое ** environment
.
Если bash
попытается сделать что-то особенное с окружением (ну ... не так ли? Это оболочка?), То у вас могут быть проблемы.
По-видимому, bash
перегружает unsetenv ()
даже до main_init ()
. Изменение кода примера на:
extern char**environ;
int __attribute__((constructor)) main_init(void)
{
int i;
printf("Unsetting LD_PRELOAD: %x\n",unsetenv("LD_PRELOAD"));
printf("LD_PRELOAD: \"%s\"\n",getenv("LD_PRELOAD"));
printf("Environ: %lx\n",environ);
printf("unsetenv: %lx\n",unsetenv);
for (i=0;environ[i];i++ ) printf("env: %s\n",environ[i]);
fflush(stdout);
FILE *fp = popen("ls", "r");
pclose(fp);
}
показывает проблему. При обычном запуске (выполняя cat
, ls
и т. Д.) Я получаю эту версию unsetenv:
unsetenv: 7f4c78fd5290
unsetenv: 7f1127317290
unsetenv: 7f1ab63a2290
однако, выполняя bash
или sh
]:
unsetenv: 46d170
Итак, вот оно. bash
обманул; -)
Так что просто измените окружение на месте, используя свой собственный unsetenv
, действующий на ** окружение
:
for (i=0;environ[i];i++ )
{
if ( strstr(environ[i],"LD_PRELOAD=") )
{
printf("hacking out LD_PRELOAD from environ[%d]\n",i);
environ[i][0] = 'D';
}
}
которая, как можно увидеть, работает в strace
:
execve("/bin/sh", ["sh", "-c", "ls"], [... "DD_PRELOAD=mylib.so" ...]) = 0
QED
(Ответ является чистым предположением, а может быть неверным).
Возможно, когда вы разветвляете свой процесс, контекст загруженных библиотек сохраняется. Итак, mylib.so
был загружен , когда вы вызывали основную программу через LD_PRELOAD
. Когда вы сбрасываете переменную и разветвляете ее, она больше не загружалась; однако он уже был загружен родительским процессом. Возможно, вам стоит явно выгрузить его после разветвления.
Вы также можете попытаться «понизить» символы в mylib.so
. Для этого снова откройте его через dlopen
с флагами, которые помещают его в конец очереди разрешения символов:
dlopen("mylib.so", RTLD_NOLOAD | RTLD_LOCAL);