使用Linux功能是否会禁用LD_PRELOAD

时间:2013-08-05 12:40:46

标签: c linux linux-kernel shared-libraries linux-capabilities

在我的自定义环境中,预加载了一个拦截器库,它运行bind()connect()等调用的特殊实现。

我看到的问题是,只要使用命令setcap显式启用应用程序,执行应用程序就无法预加载拦截器库并调用默认的libc connect()

这是预期的行为吗?如果是,那么禁用LD_PRELOAD的原因是什么?

是否可以使用任何调整或方法成功预装启用功能的库。

2 个答案:

答案 0 :(得分:5)

就像Oliver Matthews回答的那样,出于安全原因,对于setuid二进制文件和具有文件功能的二进制文件都禁用LD_PRELOAD

要在仍启用文件功能的同时预加载库,您有两个选择:

  1. 设置预加载的库setuid root

    (如果库由root拥有并标记为set-uid,则Linux动态链接器ld.so会为setuid / file-capability-enabled二进制文件预加载库。)

  2. 使用setuid root wrapper

    包装器获得完全root权限(实际和有效用户和组ID都为零),并将原始真实用户和组ID存储到例如环境变量。

    预加载的库有一个构造函数,例如

    static void my_library_init(void) __attribute__((constructor));
    static void my_library_init(void)
    {
        /* ... */
    }
    

    main()之前自动运行(但可能在其他预加载库中的其他构造函数之后,或者在预加载库所依赖的库中)。

    此构造函数获取所需的功能,通过环境变量(getenv()cap_from_text())或二进制可执行文件本身(cap_from_file("/proc/self/exe"))指定。

    构造函数必须暂时使用prctl(PR_SET_KEEPCAPS, 1)来保持身份更改的功能,并保留CAP_SETUIDCAP_SETGID功能,以便能够将身份从root更改为指定的用户和组环境变量,然后将其自身限制为最终的功能集。

  3. 这两个选项都有明显的安全考虑因素。我建议在预加载的库构造函数中进行健全性检查(并清除LD_PRELOAD)。如果有任何可疑之处,请使用_exit()立即中止该过程。

    一般情况下,我推荐第一个简单选项(实现和安全问题),但如果有某些原因无法使用,我也可以为第二种情况提供概念验证代码。 (我已经验证了两个选项在Ubuntu 12.04.2 LTS上运行,使用ext4文件系统运行3.8.0-27通用x86-64内核。)

    希望这有帮助。

答案 1 :(得分:4)

是的,这是出于安全原因(见man sudo)。

您必须使用main()(或通过包装main或类似内容)在dlopen开头的代码中显式打开库来解决此问题。