簡體   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