rpath

Жестко заданный путь поиска

В информатике rpath обозначает путь поиска во время выполнения, жестко закодированный в исполняемом файле или библиотеке . Динамически связываемые загрузчики используют rpath для поиска требуемых библиотек.

В частности, он кодирует путь к разделяемым библиотекам в заголовок исполняемого файла (или другой разделяемой библиотеки). Это значение заголовка RPATH (так названо в стандартах заголовков Executable and Linkable Format ) может либо переопределять, либо дополнять системные пути поиска динамического связывания по умолчанию.

Rpath исполняемого файла или разделяемой библиотеки — это необязательная запись в .dynamicразделе исполняемого файла ELF или разделяемых библиотек с типом DT_RPATH, называемым DT_RPATHатрибутом. Он может быть сохранен там во время компоновки компоновщиком. Такие инструменты, как chrpathи patchelfмогут создать или изменить запись позже.

Использование записи DT_RPATH динамическим компоновщиком

Различные динамические компоновщики для ELF реализуют использование атрибута DT_RPATHпо-разному.

GNU ld.so

Динамический компоновщик библиотеки GNU C ищет общие библиотеки в следующих местах в следующем порядке: [1]

  1. Пути (разделенные двоеточием) в DT_RPATHатрибуте динамического раздела двоичного файла, если он присутствует, а DT_RUNPATHатрибут не существует.
  2. Пути (разделенные двоеточием) в переменной среды LD_LIBRARY_PATH, если только исполняемый файл не является двоичным setuid/setgid, в этом случае он игнорируется, LD_LIBRARY_PATHможно переопределить, вызвав динамический компоновщик с опцией --library-path(например, /lib/ld-linux.so.2 --library-path $HOME/mylibs myprogram).
  3. Пути (разделенные двоеточием) в DT_RUNPATHатрибуте динамического раздела двоичного файла, если он присутствует.
  4. Поиск на основе ldconfigфайла кэша (часто расположенного в /etc/ld.so.cache), который содержит скомпилированный список библиотек-кандидатов, ранее найденных в расширенном пути библиотеки (установленном /etc/ld.so.conf). Однако, если двоичный файл был связан с -z nodefaultlibопцией компоновщика, библиотеки в путях библиотеки по умолчанию пропускаются.
  5. В доверенном пути по умолчанию /lib, а затем /usr/lib. Если двоичный файл был связан с -z nodefaultlibопцией компоновщика, этот шаг пропускается.

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

Примечания:

  • readelf -d <binary_name> | grep 'R.*PATH'отображает RPATH или RUNPATH двоичного файла. В gcc , например, можно указать RPATH с помощью -Wl,-rpath,/custom/rpath/.
  • Опция --inhibit-rpath LISTдинамического компоновщика указывает ему игнорировать DT_RPATHи DT_RUNPATHатрибуты имен объектов в LIST. Чтобы указать основную программу в LIST, укажите пустую строку.
  • Библиотеки, указанные переменной окружения LD_PRELOAD, а затем перечисленные в /etc/ld.so.preloadзагружаются до начала поиска. Таким образом, предварительная загрузка может использоваться для замены некоторых (или всех) обычных функций запрошенной библиотеки, или ее можно просто использовать для предоставления библиотеки, которая в противном случае не была бы найдена.
  • Статические библиотеки ищутся и связываются с файлом ELF во время компоновки и не ищутся во время выполнения.

Роль GNU ld

GNU Linker (GNU ld) реализует функцию, называемую «new-dtags», которую можно использовать для вставки rpath, имеющего более низкий приоритет, чем LD_LIBRARY_PATH переменная окружения . [2]

Если в компоновщике ( ) включена функция new-dtags --enable-new-dtags, GNU ld, помимо установки DT_RPATHатрибута, также устанавливает DT_RUNPATHатрибут в ту же строку. Во время выполнения, если динамический компоновщик находит атрибут DT_RUNPATH, он игнорирует значение атрибута DT_RPATH, с эффектом, который LD_LIBRARY_PATHпроверяется в первую очередь, а пути в DT_RUNPATHатрибуте ищутся только после этого.

Динамический компоновщик ld не ищет DT_RUNPATHместоположения для транзитивных зависимостей, в отличие от DT_RPATH. [3]

Вместо указания -rpathкомпоновщику LD_RUN_PATHможно задать переменную окружения для того же эффекта.

Solaris ld.so

Динамический компоновщик Solaris , в частности /lib/ld.soSunOS 5.8 и подобных систем, ищет библиотеки в каталогах, указанных в переменной LD_LIBRARY_PATH, прежде чем смотреть на DT_RPATHатрибут. Sun Microsystems была первой [ нужна ссылка ] , кто ввел динамическую загрузку библиотек. Позднее Sun добавила опцию rpath в ld и использовала ее в основных библиотеках в качестве дополнительной функции безопасности. GNU ld делал то же самое для поддержки динамических библиотек в стиле Sun.

Пример

$ cc  -shared  -Wl,-soname,termcap.so.4,-rpath,/lib/termcap.so.4  -o  termcap.so.4$ objdump  -x  termcap.so.4  НУЖЕН libc.so.6  SONAME termcap.so.4  RPATH /lib/termcap.so.4

В этом примере GNU или Sun ld (ld.so) ОТКАЗЫВАЕТСЯ загружать termcap для программы, которой он нужен, если файл не termcap.soнаходится в /lib/и не назван termcap.so.4. LD_LIBRARY_PATH игнорируется. Если /lib/termcap.so.4для исправления удаляется, оболочка умирает (нельзя загрузить альтернативный вариант termcap.so, и требуется спасательный диск, но также если новый termcap.so.4имеет RPATH /lib, ld.so откажется использовать для его загрузки, если он не будет затёрт /lib/termcap.so.4). Но есть и другая проблема: небезопасно копировать некоторые библиотеки в , /libпоскольку они «используются», что ещё больше ограничивает потенциального тестировщика библиотек. Более того,SONAME termcap.so.4против.SONAME termcap.soозначает, что программы, которым требуется базовая поддержка, termcap.soотклонены, поскольку указанная выше библиотека удалила доступ ABI к базовой поддержке.

$ cc  -shared  -Wl,-soname,libtermcap.so.2  -o  libtermcap.so.2$ objdump  -x  termcap.so.2  НУЖЕН libc.so.6  SONAME termcap.so.2

Старый Linux/Sun использовал вышеописанное, что позволяет пользователю указать любой программе использовать любой, termcap.soуказанный в LD_LIBRARY_PATH , или то, что находится в /usr/local/lib(n) с помощью правил поиска, таких как . Однако GNU ld всегда использует or независимо от LD_LIBRARY_PATH , поэтому сначала перемещается в и то, что упомянуто в , что позволяет использовать перемещение и или использование LD_LIBRARY_PATH для использования. Предпочтительная практика — использовать "ld.so.conf/lib/usr/lib/lib/termcap.so/usr/local/libld.so.conflibsld.so.confSONAME termcap.so" и программы проверяют версию (все библиотеки поддерживают это) для использования доступных функций, но в старых версиях это часто пропускалось из-за низкой скорости вычислений и нехватки времени на правильное кодирование.

При этом тщательно протестируйте этот тип вещей на данной платформе, прежде чем решить положиться на него. Администраторы релизов сегодня не гарантируют соблюдения прошлых руководств или документации. Некоторые разновидности UNIX компонуются и загружаются совершенно по-другому. rpath специфичен для ld, поставляемого с определенным дистрибутивом.

Наконец, как уже было сказано, rpath — это функция безопасности, однако «принудительный контроль доступа» (MAC) и другие методы могут быть столь же эффективны или даже более эффективны, чем rpath, для контроля чтения и записи библиотек.

Контроль над rpath с помощью современных компиляторов часто почти невозможен из-за длинных и запутанных скриптов make(1). Хуже того, некоторые скрипты сборки игнорируют —disable-rpath, хотя и представляют его как опцию. Было бы долго и утомительно, и, вероятно, невыполнимо, исправлять скрипты сборки в каждой нечетной программе для компиляции.

Простая "обертка" sh(1) может вызвать настоящий ld, названный ld.bin. Обертка может отфильтровывать в/из опции -rpath перед вызовом ld.

 #!/bin/sh # - здесь фильтруются параметры ld - ld.bin $opts   

Однако следует отметить, что некоторые сборки неправильно используют rpath вместо rpath-link или LD_LIBRARY_PATH или $(TOP)/dir/foo.so для поиска промежуточных продуктов, которые остаются в каталоге сборки, — таким образом, в конечном продукте возникает требование использовать rpath, что является новой проблемой, касающейся вопроса «что такое rpath».

Соображения безопасности

Использование rpath, а также runpath может представлять угрозу безопасности, если применяемое значение включает каталоги, находящиеся под контролем злоумышленника. Это может включать случаи, когда определенное значение явно ссылается на доступное для записи местоположение злоумышленника, а также случаи, когда используется относительный путь, либо через наличие . или .., через $ORIGIN и т. д., либо когда оператор каталога остается незаполненным. В частности, это может позволить эксплуатировать двоичные файлы setUID, где используется небезопасный путь. Это можно использовать, чтобы обмануть двоичный файл и заставить его загрузить вредоносные библиотеки из одного или другого каталога, находящегося под контролем злоумышленника.

Ссылки

  1. ^ "Команда Linux / Unix: ld.so". man7.org . Получено 19 февраля 2018 г. .
  2. ^ "Shared Libraries: distribution and build-system issues". Официальный сайт Haskell Compiler . Получено 4 апреля 2019 г.
  3. ^ "Ошибка № 1253638 "динамический компоновщик не использует DT_RUNPATH для транзита... : Ошибки : Пакет Eglibc : Ubuntu". 21 ноября 2013 г.
  • chrpath — инструмент для изменения DT_RPATHатрибута исполняемого файла и преобразования его в DT_RUNPATHатрибут
  • Порт FreeBSD devel/chrpath — инструмент для изменения DT_RPATH в существующих двоичных файлах ELF
  • patchELF — небольшая утилита для изменения динамического компоновщика и DT_RUNPATHатрибутов исполняемых файлов ELF .
  • [1] - Статья об атаках на компоновщик времени выполнения, включая атаки на DT_RPATH
Взято с "https://en.wikipedia.org/w/index.php?title=Rpath&oldid=1272178721"