简体   繁体   English

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

[英]How to solve process control reported by Fortify

I'm working on below process control issue reported by fortify which is described in https://vulncat.fortify.com/en/detail?id=desc.dataflow.abap.process_control#C%2FC%2B%2B我正在处理由 fortify 报告的以下过程控制问题,该问题在https://vulncat.fortify.com/en/detail?id=desc.dataflow.abap.process_control#C%2FC%2B%2B中有所描述

The function load() in filename.c calls dlopen() on line 3. The call loads a library without specifying an absolute path. filename.c 中的 function load() 在第 3 行调用 dlopen()。调用加载库时未指定绝对路径。 It could result in the program using a malicious library supplied by an attacker.它可能导致程序使用攻击者提供的恶意库。

I have below function which is getting invoked in different places of code.我有以下 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");
}

Here I'm already using absolute path, but don't understand why Fortify still reports the error.这里我已经是用绝对路径了,但是不明白为什么Fortify还是报错。

The possible recommendation from Fortify is as shown below. Fortify 的可能建议如下所示。

  1. Whenever possible, libraries should be controlled by the application and executed using an absolute path.只要有可能,库应该由应用程序控制并使用绝对路径执行。
  2. In cases where the path is not known at compile time, such as for cross-platform applications, an absolute path should be constructed from known values during execution.在编译时路径未知的情况下,例如对于跨平台应用程序,绝对路径应该在执行期间从已知值构造。

Any suggestion would be helpful.任何建议都会有所帮助。

The load function could in theory be called someplace else that doesn't pass a full path or, even worse, a variable populated by the user that isn't properly checked.理论上, load function 可以被称为其他不通过完整路径的地方,或者更糟糕的是,用户填充的变量未正确检查。

load might better be implemented as a macro in this case:在这种情况下, load可能更好地实现为宏:

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

Then when the substitution happens, dlopen is actually given a string constant specifying an absolute path that Fortify should be able to see.然后当替换发生时,实际上给dlopen一个字符串常量,指定 Fortify 应该能够看到的绝对路径。

There are two related but separate problems here:这里有两个相关但独立的问题:

  1. How to load dynamic libraries in a secure manner at run time如何在运行时以安全的方式加载动态库

  2. How to make Fortify see security is properly taken care of如何让 Fortify 看到安全得到妥善处理


The common approach that Fortify recommends, is to define a fixed path to a directory, in which plugins must be located. Fortify 推荐的常用方法是定义一个目录的固定路径,插件必须位于该目录中。 It is assumed that only those with sufficient privileges have access to that directory.假定只有具有足够权限的用户才能访问该目录。 The pattern is similar to模式类似于

#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;
}

In general, a fixed path named after the application in the /usr/lib tree, say /usr/lib/application/plugins/ can be considered secure, assuming it is installed so the directory and all its parent directories are owned by superuser and a privileged group, with no write access to the others (ie, drwxrwxr-x or drwr-xr-x ).通常,在/usr/lib树中以应用程序命名的固定路径,例如/usr/lib/application/plugins/可以被认为是安全的,假设它已安装,因此该目录及其所有父目录都由超级用户拥有并且一个特权组,对其他组没有写入权限(即drwxrwxr-xdrwr-xr-x )。

If the user can specify full path to the library, each directory along the path must be vetted, to verify if they may be modified by unprivileged users.如果用户可以指定库的完整路径,则必须审查路径上的每个目录,以验证它们是否可以被非特权用户修改。 If any are suspect, then the library is not secure.如果有任何可疑之处,则图书馆不安全。

The library file itself can be opened read-only, and a read lease (see fcntl() ) placed on it, if the process has sufficient privileges ( CAP_LEASE capability, or run as a privileged user).如果进程有足够的权限( CAP_LEASE能力,或以特权用户身份运行),库文件本身可以以只读方式打开,并在其上放置读取租约(请参阅fcntl() )。 This will fail if any process has the file open for writing, meaning another process is able to modify it while we use it.如果任何进程打开文件进行写入,这将失败,这意味着另一个进程能够在我们使用它时修改它。 If the lease is granted, then any other process trying to open the file for writing causes them to block, and this process be notified by a signal.如果租约被授予,那么任何其他试图打开文件进行写入的进程都会导致它们阻塞,并且该进程会收到信号通知。 This process can delay (but not fully block) the other process from opening the library, for up to lease-break-time, typically 45 seconds.此进程可以延迟(但不完全阻止)其他进程打开库,最长为租约中断时间,通常为 45 秒。 This way, a secure process can detect if someone (even privileged) tries to modify the plugin while it is being used.这样,安全进程可以检测是否有人(甚至特权)在使用插件时试图修改它。

With a valid read lease, it is time to examine the file ownership and mode (via fstat() using the file descriptor used to open it read-only), to see if it is owned and only modifiable by privileged users.有了有效的读取租约,就可以检查文件所有权和模式(通过fstat()使用用于以只读方式打开它的文件描述符),查看它是否为特权用户所有以及是否只能由特权用户修改。 If it is modifiable by unprivileged users, it is not secure.如果非特权用户可以修改它,则它是不安全的。

After all the above checks, given the file descriptor number FD , the path provided to dlopen() is /proc/self/fd/FD .在所有上述检查之后,给定文件描述符编号FD ,提供给dlopen()的路径是/proc/self/fd/FD This reuses the same file descriptor, ensuring we do not have a TOCTTOU race window (time of check to time of use).这将重用相同的文件描述符,确保我们没有 TOCTTOU 竞争 window(检查时间到使用时间)。


Whether Fortify recognizes the above measures, or just complains whenever it sees dlopen() used at all, I have no idea: I do not use it myself. Fortify 是否承认上述措施,或者只是在看到dlopen()被使用时抱怨,我不知道:我自己不使用它。

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

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