LD_PRELOAD влияет на нового ребенка даже после unsetenv (“LD_PRELOAD”)

мой код следующие: 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).

Подробнее

  1. Эта проблема имеет отношение к удару в некотором роде; или как команда, которую выполняет пользователь, выполненный, или как удар popen.
  2. дополнительные Ключевые факторы: 1) выполните popen из предварительно загруженной библиотеки, 2) вероятно, потребность сделать popen в разделе инициализации библиотеки.
  3. если Вы используете:

    LD_DEBUG=all LD_DEBUG_OUTPUT=/tmp/ld-debug LD_PRELOAD=./mylib.so bash
    

    вместо последней команды Вы получите много файлов ld-отладки, названных/tmp/ld-debug.*. Один для каждого разветвленного процесса. ВО ВСЕХ ЭТИХ ФАЙЛАХ Вы будете видеть, что символы сначала ищутся в mylib.so даже при том, что LD_PRELOAD был удален из среды.

7
задан avner 21 July 2010 в 09:50
поделиться

2 ответа

редактировать: так что проблема / вопрос на самом деле заключалась в следующем: как вы не можете надежно отключить 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

8
ответ дан 7 December 2019 в 01:15
поделиться

(Ответ является чистым предположением, а может быть неверным).

Возможно, когда вы разветвляете свой процесс, контекст загруженных библиотек сохраняется. Итак, mylib.so был загружен , когда вы вызывали основную программу через LD_PRELOAD . Когда вы сбрасываете переменную и разветвляете ее, она больше не загружалась; однако он уже был загружен родительским процессом. Возможно, вам стоит явно выгрузить его после разветвления.

Вы также можете попытаться «понизить» символы в mylib.so . Для этого снова откройте его через dlopen с флагами, которые помещают его в конец очереди разрешения символов:

dlopen("mylib.so", RTLD_NOLOAD | RTLD_LOCAL);

2
ответ дан 7 December 2019 в 01:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: