在 Mac OS X 上编译不受库重定向影响的二进制文件

Compiling a binary immune to library redirection on Mac OS X

我注意到在 Mac OS X 上(目前我在 运行ning Yosemite,但我在早期版本的 OS X) 每当我使用 -static 选项调用 g++(甚至 gcc)时,二进制文件的链接失败——总是由于某个库或另一个库没有被成功找到。因此,我只能生成使用共享库的二进制文件。

这是个问题,因为我有一种情况,如果不编写使用 Setuid Root 权限安装的程序,我将无法解决。我需要编写的这个程序将检查环境变量以确保它们没有任何恶意(并且它会以安全而不是抱歉的态度这样做)然后它将它的用户 ID 降级为普通用户 before 使用 exec() 的形式调用另一个程序。

这些环境安全检查将确保 other 程序可以 运行 在保证关键环境变量(例如 DYLD_LIBRARY_PATH) 没有损坏。但是这个程序 本身 可以 运行 在任何这样的保证下 - 因为它是 执行的工作的一部分这个检查在第一个地方。

那么我该如何保护这个 C++ 程序免受这样的安全漏洞的影响呢?我的第一个想法是用 -static 选项编译它 --- 但由于这在 OS X 上不起作用,有没有人有 other想法?

谢谢。

编辑:只要可执行文件是 setuid,加载器就会杀死所有 DYLD_* 环境变量。来自 the source code for dyld.cpp:

// For security, setuid programs ignore DYLD_* environment variables.
// Additionally, the DYLD_* enviroment variables are removed
// from the environment, so that any child processes don't see them.

[原始答案:] 根据 this post by Sam Marshall,您可以通过向名为“__RESTRICT”的二进制 header 添加新部分来实现,其中一个部分名为“__restrict”。您可以通过将此添加到 "Other Linker Flags":

在 Xcode 中执行此操作
-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null

忽略 DYLD_LIBRARY_PATH 的其他可能方法是将可执行文件设置为 setuid 或 setgid,或者使用授权进行签名。来自 the source code for dyld.cpp:

dyld::log("dyld: DYLD_ environment variables being ignored because ");
switch (sRestrictedReason) {
    case restrictedNot:
        break;
    case restrictedBySetGUid:
        dyld::log("main executable (%s) is setuid or setgid\n", sExecPath);
        break;
    case restrictedBySegment:
        dyld::log("main executable (%s) has __RESTRICT/__restrict section\n", sExecPath);
        break;
    case restrictedByEntitlements:
        dyld::log("main executable (%s) is code signed with entitlements\n", sExecPath);
        break;
}