在我的自定义环境中,预加载了一个拦截器库,它运行bind(),connect()等调用的特殊实现.
我看到的问题是,只要应用程序使用命令setcap显式启用功能,执行应用程序就无法预加载拦截器库并调用默认的libc connect().
这是预期的行为吗?如果是,那么禁用LD_PRELOAD的原因是什么?
解决方法
就像Oliver Matthews所回答的那样,出于安全原因,LD_PRELOAD对于setuid二进制文件和具有文件功能的二进制文件都是禁用的.
>设置预加载的库setuid root
(Linux动态链接器ld.so甚至为setuid /文件功能启用的二进制文件预加载库,如果这些库由root拥有并标记为set-uid.)
>使用setuid根包装器
包装器获得完全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_SETUID和CAP_SETGID功能,以便能够将身份从root更改为环境变量中指定的用户和组,然后再将其自身限制为最终能力集.
两种选择都有明显的安全性考虑我建议在预加载的库构造函数中进行完整性检查(并清除LD_PRELOAD).如果有任何可疑之处,请使用_exit()立即中止该过程.
一般来说,我推荐第一个简单选项(实现和安全问题),但如果有某些原因无法使用,我也可以为第二种情况提供概念验证代码. (我已经验证了两个选项在Ubuntu 12.04.2 LTS上运行,使用ext4文件系统运行3.8.0-27通用x86-64内核.)
希望这可以帮助.