繁体   English   中英

如何解决 Fortify 报告的过程控制

[英]How to solve process control reported by Fortify

我正在处理由 fortify 报告的以下过程控制问题,该问题在https://vulncat.fortify.com/en/detail?id=desc.dataflow.abap.process_control#C%2FC%2B%2B中有所描述

filename.c 中的 function load() 在第 3 行调用 dlopen()。调用加载库时未指定绝对路径。 它可能导致程序使用攻击者提供的恶意库。

我有以下 function,它在不同的代码位置被调用。

void* load(char* name)
{
    void* handle;
    handle = dlopen(name, RTLD_LAZY | RTLD_GLOBAL);
    return(handle);
}

void somefunc()
{
    void *login_module_handle = load("/home/myuser/load_this_shared_lib.so");
}

这里我已经是用绝对路径了,但是不明白为什么Fortify还是报错。

Fortify 的可能建议如下所示。

  1. 只要有可能,库应该由应用程序控制并使用绝对路径执行。
  2. 在编译时路径未知的情况下,例如对于跨平台应用程序,绝对路径应该在执行期间从已知值构造。

任何建议都会有所帮助。

理论上, load function 可以被称为其他不通过完整路径的地方,或者更糟糕的是,用户填充的变量未正确检查。

在这种情况下, load可能更好地实现为宏:

#define load(name) dlopen(name, RTLD_LAZY | RTLD_GLOBAL)

然后当替换发生时,实际上给dlopen一个字符串常量,指定 Fortify 应该能够看到的绝对路径。

这里有两个相关但独立的问题:

  1. 如何在运行时以安全的方式加载动态库

  2. 如何让 Fortify 看到安全得到妥善处理


Fortify 推荐的常用方法是定义一个目录的固定路径,插件必须位于该目录中。 假定只有具有足够权限的用户才能访问该目录。 模式类似于

#define _GNU_SOURCE

#ifndef  PLUGIN_PATH
#define  PLUGIN_PATH  "/usr/lib/thisapp/plugins"
#endif
#ifndef  PLUGIN_SUFFIX
#define  PLUGIN_SUFFIX  ".so"
#endif


// Try to load dynamic library 'name' under PLUGIN_PATH.
// Returns NULL if failed, with errno set.
// If this returns NULL and errno==0, use dlerror() to
// get the error message.
void *load(const char *name)
{
    // Empty or NULL name is not allowed, and it may not start with '.'.
    if (!name || !*name || *name == '.') {
        errno = EINVAL;
        return NULL;
    }

    // Name may not contain '/'.
    if (strchr(name, '/')) {
        errno = EINVAL;
        return NULL;
    }

    char *path = NULL;
    int pathlen = asprintf(&path, "%s/%s%s", PLUGIN_PATH, name, PLUGIN_SUFFIX);
    if (pathlen < 1 || !path) {
        errno = ENOMEM;
        return NULL;
    }

    void *handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
    free(path);
    errno = 0;  /* If handle is NULL, look at dlerror() */
    return handle;
}

通常,在/usr/lib树中以应用程序命名的固定路径,例如/usr/lib/application/plugins/可以被认为是安全的,假设它已安装,因此该目录及其所有父目录都由超级用户拥有并且一个特权组,对其他组没有写入权限(即drwxrwxr-xdrwr-xr-x )。

如果用户可以指定库的完整路径,则必须审查路径上的每个目录,以验证它们是否可以被非特权用户修改。 如果有任何可疑之处,则图书馆不安全。

如果进程有足够的权限( CAP_LEASE能力,或以特权用户身份运行),库文件本身可以以只读方式打开,并在其上放置读取租约(请参阅fcntl() )。 如果任何进程打开文件进行写入,这将失败,这意味着另一个进程能够在我们使用它时修改它。 如果租约被授予,那么任何其他试图打开文件进行写入的进程都会导致它们阻塞,并且该进程会收到信号通知。 此进程可以延迟(但不完全阻止)其他进程打开库,最长为租约中断时间,通常为 45 秒。 这样,安全进程可以检测是否有人(甚至特权)在使用插件时试图修改它。

有了有效的读取租约,就可以检查文件所有权和模式(通过fstat()使用用于以只读方式打开它的文件描述符),查看它是否为特权用户所有以及是否只能由特权用户修改。 如果非特权用户可以修改它,则它是不安全的。

在所有上述检查之后,给定文件描述符编号FD ,提供给dlopen()的路径是/proc/self/fd/FD 这将重用相同的文件描述符,确保我们没有 TOCTTOU 竞争 window(检查时间到使用时间)。


Fortify 是否承认上述措施,或者只是在看到dlopen()被使用时抱怨,我不知道:我自己不使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM