rtld-audit -
программный
интерфейс
слежения
за
динамическим
компоновщиком
#define _GNU_SOURCE /* смотрите feature_test_macros(7) */
#include <link.h>
Динамический
компоновщик
GNU
(компоновщик
времени
выполнения)
предоставляет
API слежения,
который
позволяет
приложению
получать
уведомления
о
различных
событиях
динамической
компоновки.
Данный API
очень
похож на
интерфейс
слежения,
предоставляемый
компоновщиком
времени
выполнения
из Solaris.
Необходимые
константы
и
прототипы
определены
в
<link.h>.
Чтобы
использовать
этот
интерфейс,
программист
создаёт
общую
библиотеку
функций со
стандартизованными
именами. Не
все
функции
нужно
реализовывать:
в
большинстве
случаев,
если
программист
не
заинтересован
в
конкретном
классе
отслеживаемых
событий, то
нет нужды в
создании
соответствующей
отслеживающей
функции.
Для
применения
интерфейса
слежения
переменная
окружения
LD_AUDIT должна
содержать
разделённый
двоеточиями
список
общих
библиотек,
каждая из
которых
может
реализовывать
(частично) API
слежения.
Когда
возникает
отслеживаемое
событие, из
каждой
библиотеки
вызывается
соответствующая
функция в
том
порядке, в
котором
эти
библиотеки
были
перечислены.
unsigned int la_version(unsigned int version);
This is the only function that
must be defined by an auditing library: it
performs the initial handshake between the dynamic linker and the auditing
library. When invoking this function, the dynamic linker passes, in
version, the highest version of the auditing interface that the linker
supports.
A typical implementation of this function simply returns the constant
LAV_CURRENT, which indicates the version of
<link.h> that
was used to build the audit module. If the dynamic linker does not support
this version of the audit interface, it will refuse to activate this audit
module. If the function returns zero, the dynamic linker also does not
activate this audit module.
In order to enable backwards compatibility with older dynamic linkers, an audit
module can examine the
version argument and return an earlier version
than
LAV_CURRENT, assuming the module can adjust its implementation to
match the requirements of the previous version of the audit interface. The
la_version function should not return the value of
version
without further checks because it could correspond to an interface that does
not match the
<link.h> definitions used to build the audit
module.
char *la_objsearch(const char *name, uintptr_t *cookie,
unsigned int flag);
Динамический
компоновщик
вызывает
эту
функцию
для
информирования
отслеживающей
библиотеки
при поиске
общего
объекта.
Аргумент
name
содержит
имя файла
или путь,
который
будет
разыскиваться.
В
cookie
указывается
общий
объект,
который
начал
поиск.
Аргумент
flag
устанавливается
в одно из
следующих
значений:
- LA_SER_ORIG
- Это
оригинальное
имя,
которое
будет
разыскиваться.
Как
правило,
это имя
хранится в
записи ELF DT_NEEDED
или был
передан в
аргументе
filename при
вызове dlopen(3).
- LA_SER_LIBPATH
- Значение
name было
создано с
использованием
каталога
из LD_LIBRARY_PATH.
- LA_SER_RUNPATH
- Значение
name было
создано с
использованием
каталога
из списка ELF
DT_RPATH или DT_RUNPATH.
- LA_SER_CONFIG
- Значение
name было
найдено в
кэше ldconfig(8)
(/etc/ld.so.cache).
- LA_SER_DEFAULT
- Значение
name было
найдено
при поиске
в одном из
каталогов
по
умолчанию.
- LA_SER_SECURE
- Значение
name
относится
к объекту
безопасности
(не
используется
в Linux).
Функция
la_objsearch()
возвращает
путь,
который
динамический
компоновщик
должен
использовать
в
дальнейшей
работе.
Если
возвращается
NULL, то путь
игнорируется
в
дальнейшей
работе.
Если
данная
отслеживающая
библиотека
создана
для
простого
слежения
за путями
поиска, то
должно
возвращаться
name.
void la_activity( uintptr_t *cookie, unsigned int flag);
Динамический
компоновщик
вызывает
эту
функцию
для
информирования
библиотеки
слежения о
выполнении
действия с
картой
ссылок (link-map). В
cookie задаётся
объект,
находящийся
в начале
карты
ссылок.
Когда
динамический
компоновщик
вызывает
эту
функцию,
аргумент
flag
устанавливается
в одно из
следующих
значений:
- LA_ACT_ADD
- В карту
ссылок
добавляется
новый
объект.
- LA_ACT_DELETE
- Из карты
ссылок
удаляется
объект.
- LA_ACT_CONSISTENT
- Действие
с картой
ссылок
завершено:
карта
снова
корректна
(consistent).
unsigned int la_objopen(struct link_map *map, Lmid_t lmid,
uintptr_t *cookie);
Динамический
компоновщик
вызывает
эту
функцию
при
загрузке
нового
общего
объекта.
Аргумент
map
является
указателем
на
структуру
карты
ссылок (link-map),
которая
описывает
объект.
Поле
lmid
устанавливается
в одно из
следующих
значений:
- LM_ID_BASE
- Карта
ссылок
является
частью
начального
пространства
имён (namespace).
- LM_ID_NEWLM
- Карта
ссылок
является
частью
нового
пространства
имён,
запрошенного
через dlmopen(3).
Аргумент
cookie
—
указатель
на
идентификатор
этого
объекта.
Идентификатор
используется
при
последующих
вызовах
функций
отслеживающей
библиотеки
для
идентификации
этого
объекта.
Данный
идентификатор
инициализируется
указателем
на карту
ссылок
объекта, но
отслеживающая
библиотека
может
изменить
идентификатор
на другое
значение,
которое ей
удобней
использовать
для
обращения
к объекту.
Функция
la_objopen()
возвращает
битовую
маску,
созданное
с помощью
сложения (OR)
нуля или
более
следующих
констант,
которые
позволяют
отслеживающей
библиотеке
выбирать
наблюдаемые
объекты
через
la_symbind*():
- LA_FLG_BINDTO
- Следить
за
символьными
привязками
этого
объекта.
- LA_FLG_BINDFROM
- Следить
за
символьными
привязками
из этого
объекта.
Возвращаемое
значение 0
из
la_objopen()
указывает
на то, что не
нужно
отслеживать
символьные
привязки
этого
объекта.
unsigned int la_objclose(uintptr_t *cookie);
Динамический
компоновщик
вызывает
эту
функцию
после
выполнения
конечного
кода (finalization code), но
до
выгрузки
объекта. В
cookie задаётся
идентификатор,
полученный
ранее из
вызова
la_objopen().
В текущей
реализации
значение,
возвращаемое
la_objclose(),
игнорируется.
void la_preinit(uintptr_t *cookie);
Динамический
компоновщик
вызывает
эту
функцию
после
загрузки
всех общих
объектов,
но до
передачи
управления
приложению
(то есть, до
вызова
main()).
Заметим,
что
main()
позднее
всё ещё
может
динамически
загрузить
объекты с
помощью
dlopen(3).
uintptr_t la_symbind32(Elf32_Sym *sym, unsigned int ndx,
uintptr_t *refcook, uintptr_t *defcook,
unsigned int *flags, const char *symname);
uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx,
uintptr_t *refcook, uintptr_t *defcook,
unsigned int *flags, const char *symname);
Динамический
компоновщик
вызывает
одну из
этих
функций
при
выполнении
символьной
привязки
между
двумя
общими
объектами,
которые
были
помечены
для
уведомления
функцией
la_objopen(). Функция
la_symbind32()
применяется
на 32-битных
платформах;
la_symbind64()
применяется
на 64-битных
платформах.
Аргумент
sym
является
указателем
на
структуру,
которая
содержит
информацию
о
привязываемом
символе.
Определение
структуры
находится
в
<elf.h>. Среди
полей
структуры
есть поле
st_value, которое
содержит
адрес
привязываемого
символа.
В
аргументе
ndx
указывается
индекс
символа в
таблице
символов
привязываемого
общего
объекта.
В
аргументе
refcook
указывается
общий
объект,
который
ссылается
на символ;
это тот же
идентификатор,
который
указывается
в функции
la_objopen(),
возвращающей
LA_FLG_BINDFROM. В
аргументе
defcook
указывается
общий
объект,
который
определяет
символ, на
который
производится
ссылка; это
тот же
идентификатор,
который
указывается
в функции
la_objopen(),
возвращающей
LA_FLG_BINDTO.
В
аргументе
symname
задаётся
строка,
содержащая
имя
символа.
Аргумент
flags
представляет
собой
битовую
маску,
которая
содержит
информацию
о символе и
может
использоваться
для
изменения
дальнейшего
отслеживания
этой
записи PLT (Procedure Linkage
Table).
Динамический
компоновщик
может
передавать
следующие
битовые
значения в
этом
аргументе:
- LA_SYMB_DLSYM
- Привязка
возникла
из-за
вызова dlsym(3).
- LA_SYMB_ALTVALUE
- Предыдущий
вызов la_symbind*()
вернул
альтернативное
значение
для этого
символа.
По
умолчанию,
если в
отслеживающей
библиотеке
реализованы
функции
la_pltenter()
и
la_pltexit()
(смотрите
ниже), то эти
функции
вызываются
после
la_symbind()
для
записей PLT
каждый раз
при ссылке
на символ.
Следующие
флаги
могут
объединяться
с помощью OR в
*flags для
изменения
данного
поведения
по
умолчанию:
- LA_SYMB_NOPLTENTER
- Не
вызывать
la_pltenter() для
этого
символа.
- LA_SYMB_NOPLTEXIT
- Не
вызывать
la_pltexit() для
этого
символа.
Возвращаемое
значение
la_symbind32() и
la_symbind64()
представляет
собой
адрес, по
которому
нужно
передать
управление
после
возврата
функций.
Если
отслеживающая
библиотека
просто
наблюдает
за
привязкой
символов,
то должно
возвращаться
sym->st_value. Может
возвращаться
другое
значение,
если
библиотека
хочет
передать
управление
в другое
место.
Точное имя
и типы
аргументов
данной
функции
зависят от
аппаратной
платформы
(подходящее
определение
приведено
в
<link.h>). Ниже
показано
определение
для x86-32:
Elf32_Addr la_i86_gnu_pltenter(Elf32_Sym *sym, unsigned int ndx,
uintptr_t *refcook, uintptr_t *defcook,
La_i86_regs *regs, unsigned int *flags,
const char *symname, long *framesizep);
Эта
функция
вызывается
до вызова
записи PLT
между
двумя
общими
объектами,
которые
помечены
для
уведомления
о привязке.
Значение
аргументов
sym,
ndx,
refcook,
defcook и
symname
такое же
как у
la_symbind*().
Аргумент
regs
указывает
на
структуру
(определена
в
<link.h>),
содержащую
значения
регистров,
которые
будут
использованы
для вызова
этой
записи PLT.
Аргумент
flags
указывает
на битовую
маску,
которая
сообщает
информацию
и может
использоваться
для
изменения
последующего
слежения
за этой
записью PLT;
значения
как у
la_symbind*().
The
framesizep argument points to a
long int buffer that
can be used to explicitly set the frame size used for the call to this PLT
entry. If different
la_pltenter() invocations for this symbol return
different values, then the maximum returned value is used. The
la_pltexit() function is called only if this buffer is explicitly set
to a suitable value.
Возвращаемое
la_pltenter()
значение
подобно
la_symbind*().
Точное имя
и типы
аргументов
данной
функции
зависят от
аппаратной
платформы
(подходящее
определение
приведено
в
<link.h>). Ниже
показано
определение
для x86-32:
unsigned int la_i86_gnu_pltexit(Elf32_Sym *sym, unsigned int ndx,
uintptr_t *refcook, uintptr_t *defcook,
const La_i86_regs *inregs, La_i86_retval *outregs,
const char *symname);
Эта
функция
вызывается
после
завершения
вызова
записи PLT,
выполняемой
между
двумя
общими
объектами,
которые
были
помечены
для
уведомления
при
привязке.
Функция
вызывается
перед
передачей
управления
из записи PLT
вызывающему.
Значение
аргументов
sym,
ndx,
refcook,
defcook и
symname
такое же
как у
la_symbind*().
Аргумент
inregs
указывает
на
структуру
(определена
в
<link.h>),
содержащую
значения
регистров,
используемых
для вызова
этой
записи PLT.
Аргумент
outregs
указывает
на
структуру
(определена
в
<link.h>),
содержащую
значения
для вызова
в эту
запись PLT. Эти
значения
могут
изменяться
вызывающим
и
изменения
будут
видимы
вызывающему
запись PLT.
В текущей
реализации
GNU
возвращаемое
значение
la_pltexit()
игнорируется.
Данный API не
стандартен,
но очень
похож на Solaris API,
описанный
в Solaris
Linker and Libraries Guide в
главе
Runtime Linker Auditing
Interface.
Отметим
следующие
отличия API
динамического
компоновщика
в Solaris:
- •
- Интерфейс
Solaris la_objfilter() не
поддерживается
в
реализации
GNU.
- •
- В
функциях Solaris
la_symbind32() и la_pltexit()
нет
аргумента
symname.
- •
- В
функции Solaris
la_pltexit() нет
аргументов
inregs и outregs (но
есть
аргумент
retval со
значением,
возвращаемым
функцией).
В glibc до версии
2.9
включительно,
указание
более
одной
отслеживающей
библиотеки
в
LD_AUDIT
приводит к
падению во
время
выполнения.
Это
исправлено
в glibc 2.10.
#include <link.h>
#include <stdio.h>
unsigned int
la_version(unsigned int version)
{
printf("la_version(): version = %u; LAV_CURRENT = %u\n",
version, LAV_CURRENT);
return LAV_CURRENT;
}
char *
la_objsearch(const char *name, uintptr_t *cookie, unsigned int flag)
{
printf("la_objsearch(): name = %s; cookie = %p", name, cookie);
printf("; flag = %s\n",
(flag == LA_SER_ORIG) ? "LA_SER_ORIG" :
(flag == LA_SER_LIBPATH) ? "LA_SER_LIBPATH" :
(flag == LA_SER_RUNPATH) ? "LA_SER_RUNPATH" :
(flag == LA_SER_DEFAULT) ? "LA_SER_DEFAULT" :
(flag == LA_SER_CONFIG) ? "LA_SER_CONFIG" :
(flag == LA_SER_SECURE) ? "LA_SER_SECURE" :
"???");
return name;
}
void
la_activity (uintptr_t *cookie, unsigned int flag)
{
printf("la_activity(): cookie = %p; flag = %s\n", cookie,
(flag == LA_ACT_CONSISTENT) ? "LA_ACT_CONSISTENT" :
(flag == LA_ACT_ADD) ? "LA_ACT_ADD" :
(flag == LA_ACT_DELETE) ? "LA_ACT_DELETE" :
"???");
}
unsigned int
la_objopen(struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
{
printf("la_objopen(): loading \"%s\"; lmid = %s; cookie=%p\n",
map->l_name,
(lmid == LM_ID_BASE) ? "LM_ID_BASE" :
(lmid == LM_ID_NEWLM) ? "LM_ID_NEWLM" :
"???",
cookie);
return LA_FLG_BINDTO | LA_FLG_BINDFROM;
}
unsigned int
la_objclose (uintptr_t *cookie)
{
printf("la_objclose(): %p\n", cookie);
return 0;
}
void
la_preinit(uintptr_t *cookie)
{
printf("la_preinit(): %p\n", cookie);
}
uintptr_t
la_symbind32(Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, unsigned int *flags, const char *symname)
{
printf("la_symbind32(): symname = %s; sym->st_value = %p\n",
symname, sym->st_value);
printf(" ndx = %u; flags = %#x", ndx, *flags);
printf("; refcook = %p; defcook = %p\n", refcook, defcook);
return sym->st_value;
}
uintptr_t
la_symbind64(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, unsigned int *flags, const char *symname)
{
printf("la_symbind64(): symname = %s; sym->st_value = %p\n",
symname, sym->st_value);
printf(" ndx = %u; flags = %#x", ndx, *flags);
printf("; refcook = %p; defcook = %p\n", refcook, defcook);
return sym->st_value;
}
Elf32_Addr
la_i86_gnu_pltenter(Elf32_Sym *sym, unsigned int ndx,
uintptr_t *refcook, uintptr_t *defcook, La_i86_regs *regs,
unsigned int *flags, const char *symname, long *framesizep)
{
printf("la_i86_gnu_pltenter(): %s (%p)\n", symname, sym->st_value);
return sym->st_value;
}
ldd(1),
dlopen(3),
ld.so(8),
ldconfig(8)
Русский
перевод
этой
страницы
руководства
был сделан
aereiae <
[email protected]>, Azamat Hackimov
<
[email protected]>, Dmitriy S. Seregin <
[email protected]>,
Katrin Kutepova <
[email protected]>, Lockal
<
[email protected]>, Yuri Kozlov <
[email protected]>,
Баринов
Владимир и
Иван
Павлов <
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]