RTLD-AUDIT - Linux手册页

时间:2019-08-20 18:02:01  来源:igfitidea点击:

Linux程序员手册 第7部分
更新日期: 2020-06-09

名称

rtld-audit-动态链接程序的审核API

语法

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <link.h>

说明

GNU动态链接器(运行时链接器)提供了一个审核API,该API允许在发生各种动态链接事件时通知应用程序。该API与Solaris运行时链接程序提供的审核接口非常相似。必需的常量和原型通过包括定义。

要使用此接口,程序员将创建一个共享库,该库实现一组标准的函数名。并非所有功能都需要实现:在大多数情况下,如果程序员对特定类别的审核事件不感兴趣,则无需为相应的审核功能提供任何实现。

要使用审核接口,必须将环境变量LD_AUDIT定义为包含一个以冒号分隔的共享库列表,每个共享库都可以实现(部分)审核API。当发生可审核事件时,将按照列出库的顺序在每个库中调用相应的函数。

la_version()

unsigned int la_version(unsigned int version);

这是审核库必须定义的唯一功能:它执行动态链接程序和审核库之间的初始握手。调用此功能时,动态链接程序会在版本上传递该链接程序支持的审核接口的最高版本。如有必要,审核库可以检查该版本是否足以满足其要求。

作为其函数结果,此函数应返回此审核库期望使用的审核接口的版本(可以接受返回的版本)。如果返回的值为0或大于动态链接器支持的版本,则审核库将被忽略。

la_objsearch()

char *la_objsearch(const char *name, uintptr_t *cookie,
                   unsigned int flag);

动态链接程序调用此功能以通知审核库它将要搜索共享库。 name参数是要搜索的文件名或路径名。 Cookie标识启动搜索的共享库。标志设置为以下值之一:

LA_SER_ORIG
这是要搜索的原始名称。通常,此名称来自ELF DT_NEEDED条目,或者是dlopen(3)的文件名参数。
LA_SER_LIBPATH
名称是使用LD_LIBRARY_PATH中指定的目录创建的。
LA_SER_RUNPATH
名称是使用ELF DT_RPATH或DT_RUNPATH列表中指定的目录创建的。
LA_SER_CONFIG
通过ldconfig(8)高速缓存(/etc/ld.so.cache)找到了名称。
LA_SER_DEFAULT
通过搜索默认目录之一找到名称。
LA_SER_SECURE
名称特定于安全对象(在Linux上未使用)。

作为其函数结果,la_objsearch()返回动态链接器应用于进一步处理的路径名。如果返回NULL,则将忽略此路径名以进行进一步处理。如果此审核库仅打算监视搜索路径,则应返回名称。

la_activity()

void la_activity( uintptr_t *cookie, unsigned int flag);

动态链接器调用此函数以通知审核库正在发生链接映射活动。 cookie标识链接映射顶部的对象。当动态链接程序调用此函数时,标志设置为以下值之一:

LA_ACT_ADD
新对象将添加到链接映射。
LA_ACT_DELETE
正在从链接映射中删除对象。
LA_ACT_CONSISTENT
链接地图活动已完成:地图再次保持一致。

la_objopen()

unsigned int la_objopen(struct link_map *map, Lmid_t lmid,
                        uintptr_t *cookie);

加载新的共享库时,动态链接器将调用此函数。 map参数是指向描述对象的链接映射结构的指针。 lmid字段具有以下值之一

LM_ID_BASE
链接映射是初始名称空间的一部分。
LM_ID_NEWLM
链接映射是通过dlmopen(3)请求的新名称空间的一部分。

cookie是指向该对象标识符的指针。该标识符提供给以后对审核库中的函数的调用,以标识该对象。该标识符被初始化为指向对象的链接映射,但是审计库可以将标识符更改为它可能更喜欢用来标识对象的其他值。

作为返回值,la_objopen()返回通过对零个或多个以下常量进行"或"运算而创建的位掩码,这使审核库可以选择要由la_symbind *()监视的对象:

LA_FLG_BINDTO
审核与此对象的符号绑定。
LA_FLG_BINDFROM
审核来自此对象的符号绑定。

la_objopen()的返回值为0表示不应为此对象审核任何符号绑定。

la_objclose()

unsigned int la_objclose(uintptr_t *cookie);

动态链接器在对象的任何完成代码执行完毕之后,对象卸载之前调用此函数。 cookie参数是从先前调用la_objopen()获得的标识符。

在当前实现中,由la_objclose()返回的值将被忽略。

la_preinit()

void la_preinit(uintptr_t *cookie);

动态链接程序在所有共享对象加载完毕之后,将控制权传递给应用程序之前(即,在调用main()之前)调用此函数。请注意,main()稍后仍可以使用dlopen(3)动态加载对象。

la_symbind*()

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()标记为用于审核通知。在32位平台上使用了la_symbind32()函数。在64位平台上使用了la_symbind64()函数。

sym参数是指向结构的指针,该结构提供有关所绑定符号的信息。结构定义在中显示。在此结构的字段中,st_value表示符号绑定到的地址。

ndx参数给出绑定共享对象的符号表中符号的索引。

refcook参数标识正在进行符号引用的共享库。这是提供给返回LA_FLG_BINDFROM的la_objopen()函数的相同标识符。 defcook参数标识定义引用符号的共享库。这是提供给返回LA_FLG_BINDTO的la_objopen()函数的相同标识符。

symname参数指向包含符号名称的字符串。

flags参数是一个位掩码,它既提供有关符号的信息,又可用于修改此PLT(过程链接表)条目的进一步审核。动态链接器可以在此参数中提供以下位值:

LA_SYMB_DLSYM
绑定是由于调用dlsym(3)导致的。
LA_SYMB_ALTVALUE
先前的la_symbind *()调用返回了此符号的备用值。

默认情况下,如果审核库实现la_pltenter()和la_pltexit()函数(请参见下文),则每次引用该符号时,都会在la_symbind()之后为PLT条目调用这些函数。可以将以下标志与*标志进行或运算,以更改此默认行为:

LA_SYMB_NOPLTENTER
不要为此符号调用la_pltenter()。
LA_SYMB_NOPLTEXIT
不要为此符号调用la_pltexit()。

la_symbind32()和la_symbind64()的返回值是函数返回后应将控件传递到的地址。如果审核库仅监视符号绑定,则它应返回sym-> st_value。如果库希望将控制权定向到备用位置,则可能会返回不同的值。

la_pltenter()

此函数的确切名称和参数类型取决于硬件平台。 (适当的定义由提供。)这是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 int *framesizep);

在已标记为绑定通知的两个共享对象之间,将在调用PLT条目之前调用此函数。

symndxrefcook,defcook和symname与la_symbind *()相同。

regs参数指向一个结构(在中定义),该结构包含用于调用此PLT条目的寄存器的值。

flags参数指向一个位掩码,该位掩码传达有关此PLT条目的信息,并且可用于修改此PLT条目的后续审核,例如la_symbind *()。

framesizep参数指向一个长整数缓冲区,该缓冲区可用于显式设置用于调用此PLT条目的帧大小。如果对此符号的不同la_pltenter()调用返回不同的值,则使用最大返回值。仅当此缓冲区显式设置为合适的值时,才会调用la_pltexit()函数。

la_pltenter()的返回值与la_symbind *()相同。

la_pltexit()

此函数的确切名称和参数类型取决于硬件平台。 (适当的定义由提供。)这是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条目的调用者之前被调用。

symndxrefcook,defcook和symname与la_symbind *()相同。

inregs参数指向一个结构(在中定义),该结构包含用于调用此PLT条目的寄存器的值。 outregs参数指向一个结构(在中定义),该结构包含对此PLT条目的调用的返回值。这些值可以由调用方修改,并且更改对PLT条目的调用方可见。

在当前的GNU实现中,忽略la_pltexit()的返回值。

遵循规范

该API是非标准的,但与《 Solaris Linker and Libraries Guide》中的" Runtime Linker Auditing Interface"一章中描述的Solaris API非常相似。

备注

请注意与Solaris动态链接器审核API的以下区别:

*
GNU实现不支持Solaris la_objfilter()接口。
*
Solaris la_symbind32()和la_pltexit()函数不提供symname参数。
*
Solaris la_pltexit()函数不提供inregs和outregs参数(但提供具有函数返回值的retval参数)。

BUGS

在2.9及更高版本的glibc中,在LD_AUDIT中指定多个审计库会导致运行时崩溃。据报道,此问题已在glibc 2.10中修复。

示例

#include <link.h>
#include <stdio.h>

unsigned int
la_version(unsigned int version)
{
    printf("la_version(): %d\n", version);

    return version;
}

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 = %d; flags = 0x%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 = %d; flags = 0x%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 int *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)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/