在我的自定义环境中,预加载了一个拦截器库,它运行bind()
,connect()
等调用的特殊实现。
我看到的问题是每当使用命令setcap
显式启用应用程序时,执行应用程序无法预加载拦截器库并调用默认的libc connect()
。
这是预期的行为吗?如果是的话,可能是什么原因禁用LD_PRELOAD
?
是否有任何调整或方法可用于成功预加载启用功能的库。
就像Oliver Matthews回答的那样,出于安全原因,LD_PRELOAD
对于setuid二进制文件和具有文件功能的二进制文件都是禁用的。
要在仍启用文件功能的同时预加载库,您有两个选择:
ld.so
甚至为setuid /文件功能启用的二进制文件预加载库,如果这些库由root拥有并标记为set-uid。)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内核。)
希望这可以帮助。
是的,这是出于安全原因(参见man sudo
)。
您必须通过使用main()
(或通过包装main或类似物)在dlopen
开头的代码中显式打开库来解决它。