天天看點

Read-only dynamic data

lwn文章翻譯,原文 連結

簡介

本文主要講述的是一種動态記憶體的隻讀保護機制。

原文

核心開發者可以對想保護的資料設定為read-only權限,借助于MMU來避免惡意攻擊者的篡改。kernel目前已經支援隻讀記憶體保護,但這些記憶體必須在作業系統自舉完成前被初始化,是以局限性很大。Igor Stoppa的一組

patch

彌補了這篇空白,他提出一組新API。

已有的隻讀保護機制,最直覺當屬const修複符,但它是編譯時檢查。

post-init read-only data mechanism

是kernel目前已支援的隻讀保護機制,它來自于grsecurity patch,所有的資料必須在作業系統引導階段完成初始化,在此之後則不允許修改。那麼作業系統初始化後,如果想保護動态申請的記憶體該怎麼辦呢?目前kernel并無此類機制,Igor Stoppa則提出了"protectable memory allocator"(簡稱pmalloc),核心思想是建立一個pool,所有的隻讀對象從pool中配置設定。API如下:

  • 建立pool對象,傳回pool句柄:
#include <linux/pmalloc.h>

    struct pmalloc_pool *pool = pmalloc_create_pool();           
  • 從pool中申請記憶體,傳回記憶體位址,此時可讀寫:
void *pmalloc(struct pmalloc_pool *pool, size_t size);
    void *pzalloc(struct pmalloc_pool *pool, size_t size);
    void *pmalloc_array(struct pmalloc_pool *pool, size_t n, size_t size);
    void *pcalloc(struct pmalloc_pool *pool, size_t n, size_t size);
    char *pstrdup(struct pmalloc_pool *pool, const char *s);           

上述API與使用者态的libc接口很像,其基礎接口是pmalloc(),其他都是一些變種。

  • 使用者對傳回的位址進行初始化,然後設定read-only權限,傳回後則不能再進行修改:
void pmalloc_protect_pool(struct pmalloc_pool *pool);           

調用此函數之後,使用者可以接着申請記憶體,即此API修改的是已申請記憶體相對應的頁表權限。由于頁表權限都是以4k為機關,是以此處有可能造成記憶體浪費。

  • 銷毀:
void pmalloc_destroy_pool(struct pmalloc_pool *pool);           

(譯者注:pmalloc并未提供free()接口,是以作為allocater而言,其實作是比較簡單的。當然,它的目的是安全,而不是記憶體配置設定。)

pmalloc()是基于vmalloc(),是以不能在原子上下文中使用。需要注意的是,pmalloc是通過修改vmalloc()申請的記憶體位址頁表權限,是以攻擊者完全可以繞過此處的位址,而直接通過system memory map來篡改資料。(譯者注:有點像棧上的const局部變量,可以通過指針直接修改。)

最後,pmalloc這一組patch還缺乏明确的使用案例,社群也不打算直接merge此類缺少use case的patch,後續待觀望。

譯者總結

純從安全角度考慮,pmalloc無法做到絕對安全。如果攻擊者已經取得核心态的可寫權限,那麼可以直接修改頁表項獲得pmalloc申請對象的可寫權限。譯者覺得pmalloc機制更适合用于發現kernel自身的代碼bug,保留第一案發現場,這一點對于核心開發調試具有很重要的意義。pmalloc不支援free,這一點會限制其使用場景;不過若需支援free,allocator邏輯的複雜度就上去了,有點小題大做。pmalloc還需要更多的use case來證明其價值。

繼續閱讀