Используя dlopen, как я могу справиться с изменениями в файле библиотеки, который я загрузил?

Всегда добавляйте пункт использования.

13
задан kdt 17 October 2009 в 11:47
поделиться

5 ответов

Если вы rm библиотеку перед установкой новой, я думаю, ваша система сохранит выделенный индексный дескриптор, файл открытым и вашу программу будет работать. (И когда ваша программа, наконец, завершает работу, освобождаются файловые ресурсы, которые в основном скрыты, но все еще существуют.)

Обновление : Хорошо, пост-разъяснение. Динамический компоновщик фактически полностью «решает» эту проблему, передав флаг MAP_COPY , если он доступен, в mmap (2) . Однако MAP_COPY не существует в Linux и не планируется в будущем. Второй лучший вариант - MAP_DENYWRITE , который, как мне кажется, действительно используется загрузчиком, и который находится в Linux API, и что делал Linux. Он записывает ошибки во время отображения региона. Он должен по-прежнему позволять перезапуск и замену. Проблема здесь в том, что любой, у кого есть доступ для чтения к файлу, может сопоставить его и заблокировать запись, что открывает локальную дыру для DoS. (Рассмотрим / etc / utmp . Есть предложение использовать бит разрешения на выполнение, чтобы исправить это.)

Вам это не понравится, но есть тривиальный патч ядра, который восстановит MAP_DENYWRITE функциональность. В Linux все еще есть эта функция, она просто очищает бит в случае mmap (2) . Вы должны исправить это в коде, который дублируется для каждой архитектуры, для ia32 я считаю, что это файл arch / x86 / ia32 / sys_ia32.c .

asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
                            unsigned long prot, unsigned long flags,
                            unsigned long fd, unsigned long pgoff)
{
        struct mm_struct *mm = current->mm;
        unsigned long error;
        struct file *file = NULL;

        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); // fix this line to not clear MAP_DENYWRITE

Это должно быть нормально, если вы этого не сделаете. не иметь каких-либо злонамеренных локальных пользователей с учетными данными. Это не удаленный DoS, а только локальный.

18
ответ дан 1 December 2019 в 20:43
поделиться

Если вы устанавливаете новую версию библиотеки, правильная процедура - создать новый файл в том же каталоге, а затем переименуйте его поверх старого. Старый файл останется, пока он открыт, и продолжит использоваться.

Менеджеры пакетов, такие как RPM, делают это автоматически - так что вы можете обновлять разделяемые библиотеки и исполняемые файлы во время их работы - но старые версии продолжают работать.

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

6
ответ дан 1 December 2019 в 20:43
поделиться

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

Если mprotect не работает (возможно, исходный файл был открыт только для чтения), то вы можете скопировать регион в другое место, переназначить область (используя mmap ) в частную, доступную для записи область, затем скопируйте область обратно.

Я бы хотел, чтобы в ОС было «преобразование этой доступной только для чтения области в область копирования при записи» . Однако я не думаю, что что-то подобное существует.

В любом из этих сценариев, по-прежнему существует окно уязвимости - кто-то может изменить библиотеку, пока dlopen вызывает инициализаторы или до того, как произойдет ваш вызов переназначения. Вы небезопасны, если не сможете исправить динамический компоновщик, как описывает @DigitalRoss.

Кто вообще редактирует ваши библиотеки из-под вас? Найдите этого человека и ударьте его сковородой по голове.

1
ответ дан 1 December 2019 в 20:43
поделиться

Невозможно защититься от перезаписи вашей библиотеки кем-либо, если у них есть разрешение на запись в файл.

Поскольку память dlopen отображает файл библиотеки, все изменения в файле видны в каждом открытом процессе.

Функция dlopen использует отображение памяти, потому что это наиболее эффективный с точки зрения памяти способ использования разделяемых библиотек. Частная копия будет тратить память.

Как говорили другие, правильный способ заменить разделяемую библиотеку в Unix - это использовать unlink или переименование, не , чтобы перезаписать библиотеку новой копией. Команда install сделает это правильно.

4
ответ дан 1 December 2019 в 20:43
поделиться

Это интригующий вопрос. Я ненавижу находить подобные дыры в Linux и люблю искать способы их исправить.

Мое предложение вдохновлено ответом @Paul Tomblin на этот вопрос о временных файлах в Linux . Некоторые из других ответов здесь предполагают существование этого механизма, но не описывают метод его использования из клиентского приложения, как вы просили.

Я не тестировал это, поэтому я не знаю, насколько хорошо он будет работать . Кроме того, могут возникнуть незначительные проблемы безопасности, связанные с состоянием гонки, связанным с коротким периодом времени между созданием временного файла и его отключением. Кроме того, вы уже отметили возможность создания копии библиотеки, что я и предлагаю. Мой поворот в том, что ваша временная копия существует как запись в файловой системе только мгновение, независимо от того, как долго вы фактически держите библиотеку открытой.

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

  1. скопируйте файл во временное место, возможно, начиная с mkstemp ()
  2. загрузите временную копию библиотеки с помощью dlopen ()
  3. unlink () временный файл
  4. продолжайте как обычно, ресурсы файла будут автоматически удаляется при использовании dlclose ()

Было бы неплохо, если бы существовал действительно простой способ выполнить шаг «копировать файл», не требуя от вас фактического копирования файла. На ум приходит жесткое связывание, но я не думаю, что это сработает для этих целей. Было бы идеально, если бы в Linux был механизм копирования при записи, который был бы таким же простым в использовании, как link (), но я не знаю о таком средстве.

Изменить: ответ @Zan Lynx указывает на то, что создание собственных копий динамических библиотек может быть расточительным, если они реплицируются в несколько процессов. Поэтому мое предложение, вероятно, имеет смысл только в том случае, если оно применяется разумно - только к тем библиотекам, которые подвержены риску быть растоптанными (предположительно, небольшое подмножество всех библиотек, которое не включает файлы в / lib или /usr/lib).

0
ответ дан 1 December 2019 в 20:43
поделиться
Другие вопросы по тегам:

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