在我的自定义环境中,预加载了一个拦截器库,它运行bind()、connect()等的特殊实现。电话我看到的问题是,每当应用程序使用命令setcap显式启用功能时,执行应用程序时无法预加载拦截器库并调用默认libc connect()。这是预期的行为吗?如果是,禁用LD_PRELOAD的原因是什么?是否有任何调整或方法可以用来成功地预加载库与功能启用?
bind()
connect()
setcap
LD_PRELOAD
doinxwow1#
就像奥利弗马修斯回答的那样,出于安全原因,LD_PRELOAD对setuid二进制文件和具有文件功能的二进制文件都是禁用的。要在启用文件功能的同时预加载库,您有两个选项:1.设置预加载的库setuid根(The Linux动态链接器ld.so会预加载库,即使对于启用了setuid/文件功能的二进制文件,如果库由root所有并标记为set-uid。)1.使用setuid根 PackagePackage 器获得完全的根权限(真实的和有效的用户和组ID均为零),并将原始的真实的用户和组ID存储到例如环境变量。预加载的库有一个构造函数,例如
ld.so
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上运行3.8.0-27-generic x86-64内核,使用ext4文件系统。希望这对你有帮助。
main()
getenv()
cap_from_text()
cap_from_file("/proc/self/exe")
prctl(PR_SET_KEEPCAPS, 1)
CAP_SETUID
CAP_SETGID
_exit()
tcbh2hod2#
是的,这是出于安全原因(参见man sudo)。您必须通过在dlopen的开始使用main()从代码中显式打开库(或通过 Package main或类似方法)来解决它。
man sudo
dlopen
50few1ms3#
要完成nominal-animal的回答,对于选项1(设置预加载库setuid root),manual指定:在安全执行模式下,包含斜杠的预加载路径名将被忽略。因此,只需指定库的文件名(而不是带斜杠的路径名)。此外,共享对象仅从标准搜索目录中预加载,并且仅当它们启用了set-user-ID模式位(这不是典型的)时才预加载。因此,库必须存储在标准搜索目录集中。
3条答案
按热度按时间doinxwow1#
就像奥利弗马修斯回答的那样,出于安全原因,
LD_PRELOAD
对setuid二进制文件和具有文件功能的二进制文件都是禁用的。要在启用文件功能的同时预加载库,您有两个选项:
1.设置预加载的库setuid根
(The Linux动态链接器
ld.so
会预加载库,即使对于启用了setuid/文件功能的二进制文件,如果库由root所有并标记为set-uid。)1.使用setuid根 Package
Package 器获得完全的根权限(真实的和有效的用户和组ID均为零),并将原始的真实的用户和组ID存储到例如环境变量。
预加载的库有一个构造函数,例如
它在
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上运行3.8.0-27-generic x86-64内核,使用ext4文件系统。
希望这对你有帮助。
tcbh2hod2#
是的,这是出于安全原因(参见
man sudo
)。您必须通过在
dlopen
的开始使用main()
从代码中显式打开库(或通过 Package main或类似方法)来解决它。50few1ms3#
要完成nominal-animal的回答,对于选项1(设置预加载库setuid root),manual指定:
在安全执行模式下,包含斜杠的预加载路径名将被忽略。
因此,只需指定库的文件名(而不是带斜杠的路径名)。
此外,共享对象仅从标准搜索目录中预加载,并且仅当它们启用了set-user-ID模式位(这不是典型的)时才预加载。
因此,库必须存储在标准搜索目录集中。